Friday, October 31, 2025

workflow auto approval code in X++

 auto approval code:-

      WorkflowWorkItemTable           WorkflowWorkItemTable;
      WorkflowTrackingStatusTable     WorkflowTrackingStatusTable;

 

 

                select   WorkflowWorkItemTable 
                    join WorkflowTrackingStatusTable
                    where WorkflowWorkItemTable.CorrelationId == WorkflowTrackingStatusTable.CorrelationId
&& WorkflowTrackingStatusTable.ContextRecId == _newBudgetTransactionHeader.recid;

 

                WorkflowWorkItemActionManager::dispatchWorkItemAction(
                                WorkflowWorkItemTable,
                                "Auto Approve by ADMIN", // comment
                            curUserId(), //  user ID
                                WorkflowWorkItemActionType::Complete,
                              menuItemDisplayStr(BudgetTransactionHeaderWorkflowDropDialog) //  menu item action approval workflow
                            );



WorkFlow Auto sumbit code in X++

 auto sumbitted of workflow code in X++

Workflow::activateFromWorkflowType(workFlowTypeStr("BudgetRegisterEntryReview"),newBudgetTransactionHeader.RecId,"submitted",NoYes::Yes,curUserId());

                        ttsbegin;

                        newBudgetTransactionHeader.selectForUpdate(true);

                        newBudgetTransactionHeader.WorkflowStatus              = BudgetTransactionWorkflowStatus::Submitted;

                        newBudgetTransactionHeader.doUpdate();

                        ttscommit;

Monday, October 6, 2025

How to Control Edit Access for Sales Tax Fields in PR Lines Through Configuration in D365 Finance & Operations

 To provide a configuration-driven approach for controlling edit access to the Item Sales Tax Group and Sales Tax Group fields on Purchase Requisition (PR) lines.

When the toggle “Enable Tax Group configuration under PR lines” is enabled, users can edit these fields at specific PR workflow stages — in Draft and Finance Review states. When the toggle is disabled, editing is not allowed at any stage.

Configuration Steps:-
Navigation: Procurement and sourcing > Setup > Procurement and sourcing parameters > Configurations
Field: Purchase Requisition Line Sales Tax Group
Purpose: Controls whether users can edit the Item Sales Tax Group and Sales Tax Group fields on Purchase Requisition lines.
When Toggle Enabled (Yes): The Item Sales Tax Group and Sales Tax Group fields on PR lines are editable only when the PR status is Draft or Finance Review.

Code:-

[ExtensionOf(formDataSourceStr(PurchReqTable, PurchReqLine))]
internal final class PurchReqTable_PurchReqLine_Extension
{
    public int active()
    {
        FormDataSource  formDataSource = this as formDataSource;
        int ret = next active();

        PurchReqTable       purchreqTable;
        HcmWorker           hcmWorker;
        PurchReqLine        purchreqline = formDataSource.cursor();
        PurchParameters     purchParameters = PurchParameters::find();
        DirPersonUser       personUser;
        UserInfo            userInfo;
        str                 userId;
        UserGroupList       userGroupList;

        if (purchParameters.prlinesalestaxitemgroup == NoYes::Yes)
        {
            select purchreqTable
                where purchreqTable.RecId == purchreqline.purchReqTable;

            select hcmWorker
                where hcmWorker.RecId == purchreqline.Requisitioner;

            select personUser
                where personUser.PersonParty == hcmWorker.Person;

            select * from userInfo
                where userInfo.id == personUser.User;

            // Editable when PR is in Draft status and created by current user
            if (userInfo.id == curUserId() && purchreqTable.PurchReqStatus == "Draft")
            {
                formDataSource.allowEdit(true);
                formDataSource.object(fieldNum(PurchReqLine, TaxItemGroup)).enabled(true);
                formDataSource.object(fieldNum(PurchReqLine, TaxItemGroup)).allowEdit(true);
                formDataSource.object(fieldNum(PurchReqLine, TaxGroup)).enabled(true);
                formDataSource.object(fieldNum(PurchReqLine, TaxGroup)).allowEdit(true);
            }

            // For Finance Review stage
            WorkflowTrackingStatusTable workflowTrackingStatusTable;
            WorkflowWorkItemTable       workflowWorkItemTable;
            UserInfo                    userInfoloc;
            boolean                     isCurUser;

            FormTabPageControl tabItem                = this.formRun().design().controlName("tabItem") as FormTabPageControl;
            FormTabPageControl tabGeneralLine         = this.formRun().design().controlName("tabGeneralLine") as FormTabPageControl;
            FormTabPageControl tabProject             = this.formRun().design().controlName("tabProject") as FormTabPageControl;
            FormTabPageControl tabQuestionnaire       = this.formRun().design().controlName("tabQuestionnaire") as FormTabPageControl;
            FormTabPageControl tabFixedAsset          = this.formRun().design().controlName("tabFixedAsset") as FormTabPageControl;
            FormTabPageControl tabInventoryDimensions = this.formRun().design().controlName("tabInventoryDimensions") as FormTabPageControl;
            FormTabPageControl tabFinancialDimensions = this.formRun().design().controlName("tabFinancialDimensions") as FormTabPageControl;
            FormTabPageControl tabAddress             = this.formRun().design().controlName("tabAddress") as FormTabPageControl;

            if (purchreqTable.PurchReqStatus == "Finance Review")
            {
                while select workflowWorkItemTable
                    where workflowWorkItemTable.Type == WorkflowWorkItemType::WorkItem
                        && workflowWorkItemTable.Status == WorkflowWorkItemStatus::Pending
                    join workflowTrackingStatusTable
                        where workflowWorkItemTable.CorrelationId == workflowTrackingStatusTable.CorrelationId
                            && workflowTrackingStatusTable.ContextTableId == purchreqTable.TableId
                            && workflowTrackingStatusTable.ContextRecId == purchreqTable.RecId
                            && workflowTrackingStatusTable.TrackingStatus == WorkflowTrackingStatus::Pending
                    join userInfoloc
                        where workflowWorkItemTable.UserId == userInfoloc.id
                {
                    if (userInfoloc.id == curUserId())
                    {
                        isCurUser = true;
                        break;
                    }
                }

                if (isCurUser)
                {
                    formDataSource.allowEdit(true);
                    formDataSource.object(fieldNum(PurchReqLine, TaxItemGroup)).enabled(true);
                    formDataSource.object(fieldNum(PurchReqLine, TaxItemGroup)).allowEdit(true);
                    formDataSource.object(fieldNum(PurchReqLine, TaxGroup)).enabled(true);
                    formDataSource.object(fieldNum(PurchReqLine, TaxGroup)).allowEdit(true);

                    formDataSource.object(fieldNum(PurchReqLine, PurchPrice)).allowEdit(false);
                    formDataSource.object(fieldNum(PurchReqLine, CurrencyCode)).allowEdit(false);
                    formDataSource.object(fieldNum(PurchReqLine, IsPrepayment)).allowEdit(false);
                    formDataSource.object(fieldNum(PurchReqLine, LineComplete)).allowEdit(false);

                    tabItem.allowEdit(false);
                    tabGeneralLine.allowEdit(false);
                    tabProject.allowEdit(false);
                    tabQuestionnaire.allowEdit(false);
                    tabFixedAsset.allowEdit(false);
                    tabInventoryDimensions.allowEdit(false);
                    tabFinancialDimensions.allowEdit(false);
                    tabAddress.allowEdit(false);
                }
            }
        }

        return ret;
    }
}











Tuesday, September 23, 2025

Automating Consolidate Account Updates for New Voucher Transactions in D365 Finance and Operations

 Ensure the Consolidate Account field is automatically updated for all new voucher transactions based on the Consolidate MainAccount setup, to maintain consistency in financial consolidation and reporting.

[ExtensionOf(classStr(LedgerVoucherTransObject))]

internal final class LedgerVoucherTransObject_Extension

{

    public void initFromLedgerPostingTransaction(

        LedgerPostingTransactionTmp _ledgerPostingTransaction,

        LedgerPostingTransactionProjectTmp _projectPostingTransaction)

    {

        next initFromLedgerPostingTransaction(_ledgerPostingTransaction, _projectPostingTransaction);


        MainAccountConsolidateAccount   consolidationAccount;

        LedgerParameters                ledgerParameters = ledgerParameters::find();


        RecId mainAccount = MainAccount::findByLedgerDimension(generalJournalAccountEntry.ledgerDimension).RecId;


        select firstonly consolidationAccount

            where consolidationAccount.MainAccount == mainAccount

                && consolidationAccount.ConsolidateAccountGroup == ledgerParameters.ConsolidateAccountGroup;


        generalJournalAccountEntry.ConsolidateAccountName   = consolidationAccount.Name;

        generalJournalAccountEntry.ConsolidationMainAccount = consolidationAccount.ConsolidationMainAccount;

    }

}

====================================================================

Automating Consolidation Account Updates During Subledger Journal Transfer in D365 Finance

[ExtensionOf(classStr(SubledgerJournalTransferCommand))]

internal final class SubledgerJournalTransferCommand_Extension

{

    public void executeTransfer(SubledgerJournalTransferRequest subledgerJournalTransferRequest)

    {

        GeneralJournalAccountEntry      generalJournalAccountEntry;

        GeneralJournalEntry             generalJournalEntryLoc;

        SubledgerJournalEntry           subledgerJournalEntry;

        MainAccountConsolidateAccount   consolidateAccount;

        LedgerParameters                ledgerParameters;


        next executeTransfer(subledgerJournalTransferRequest);

       

        // Added by Gopi

        while select generalJournalEntryLoc

            join subledgerJournalEntry

            where subledgerJournalEntry.TransferId == generalJournalEntryLoc.TransferId

                && subledgerJournalEntry.Status == SubledgerJournalEntryStatus::Transferred

                && subledgerJournalEntry.TransferId == transferidVal

        {

            changecompany(generalJournalEntryLoc.SubledgerVoucherDataAreaId)

            {

                select crosscompany ledgerParameters

                    where ledgerParameters.DataAreaId == generalJournalEntryLoc.SubledgerVoucherDataAreaId;


                if (ledgerParameters.ConsolidateAccountGroup)

                {

                    while select forupdate generalJournalAccountEntry

                        where generalJournalAccountEntry.GeneralJournalEntry == generalJournalEntryLoc.RecId

                    {

                        select firstonly consolidateAccount

                            where consolidateAccount.MainAccount == generalJournalAccountEntry.MainAccount

                                && consolidateAccount.ConsolidateAccountGroup == ledgerParameters.ConsolidateAccountGroup;


                        ttsbegin;

                        generalJournalAccountEntry.ConsolidateAccountName       = consolidateAccount.Name;

                        generalJournalAccountEntry.ConsolidationMainAccount     = consolidateAccount.ConsolidationMainAccount;

                        generalJournalAccountEntry.doUpdate();

                        ttscommit;

                    }

                }

            }

        }

    }

}

Update Consolidate MainAccount for old records

 Update existing records to ensure the Consolidation Account field is correctly populated based on the Consolidate MainAccount setup.

1. Contract Class:-

[DataContractAttribute]

[SysOperationAlwaysInitializeAttribute]

internal final class UpdateConsolidateAccountContract 

    implements SysOperationValidatable, SysOperationInitializable

{

    TransDate fromDate;


    [DataMemberAttribute,

     SysOperationLabel(literalStr("Transaction date"))]

    public TransDate parmFromDate(TransDate _fromDate = fromDate)

    {

        fromDate = _fromDate;

        return fromDate;

    }


    public boolean validate()

    {

        boolean isValid = true;


        if (!fromDate)

        {

            isValid = checkFailed("Date must be filled in.");

        }


        return isValid;

    }


    public void initialize()

    {

        fromDate = mkDate(1, 1, 2025);

    }

}


2. Service Class:-

internal final class UpdateConsolidateAccountService extends SysOperationServiceBase

{

    public void processOperation(UpdateConsolidateAccountContract contract)

    {

        GeneralJournalAccountEntry      generalJournalAccountEntry;

        GeneralJournalEntry             generalJournalEntry;

        MainAccountConsolidateAccount   consolidationAccount;

        LedgerParameters                ledgerParameters;

        TransDate                       transactionDate = contract.parmFromDate();


        select ledgerParameters

            where ledgerParameters.DataAreaId == curExt();

        

        if (ledgerParameters.ConsolidateAccountGroup)

        {

            while select forupdate generalJournalAccountEntry

                join generalJournalEntry

                    where generalJournalAccountEntry.GeneralJournalEntry == generalJournalEntry.RecId

                       && generalJournalAccountEntry.ConsolidationMainAccount == ""

                       && generalJournalEntry.SubledgerVoucherDataAreaId == curExt()

                       && generalJournalEntry.AccountingDate >= transactionDate

            {

                try

                {

                    select firstonly consolidationAccount

                        where consolidationAccount.MainAccount == generalJournalAccountEntry.MainAccount

                           && consolidationAccount.ConsolidateAccountGroup == ledgerParameters.ConsolidateAccountGroup;

                

                    if (consolidationAccount)

                    {

                        ttsBegin;

                        generalJournalAccountEntry.ConsolidationMainAccount = consolidationAccount.ConsolidationMainAccount;

                        generalJournalAccountEntry.ConsolidateAccountName   = consolidationAccount.Name;

                        generalJournalAccountEntry.doUpdate();

                        ttsCommit;

                    }

                }

                catch

                {

                    error(UpdateConsolidateAccountService::getError());

                    continue;

                }

            }

        }

    }


    public static str getError()

    {

        SysInfologEnumerator      sysInfologEnumerator;

        SysInfologMessageStruct   infoMessageStruct;

        str                       logMessage;

        str                       logString;

        int                       i;


        #Define.NewLine('\n')

        sysInfologEnumerator = SysInfologEnumerator::newData(infolog.infologData());


        while (sysInfologEnumerator.moveNext())

        {

            i = 1;

            if (logMessage)

            {

                logMessage += #NewLine;

            }

            infoMessageStruct = SysInfologMessageStruct::construct(sysInfologEnumerator.currentMessage());

            while (i <= infoMessageStruct.prefixDepth())

            {

                logString += infoMessageStruct.preFixTextElement(i) + '. ';

                i++;

            }

            logString += infoMessageStruct.message();

            logMessage += infoMessageStruct.message();

        }


        infolog().clear();

        return logMessage;

    }

}


3. controller class:-

internal final class UpdateConsolidateAccountController extends SysOperationServiceController

{

    public void new()

    {

        super();

        this.parmClassName(classStr(UpdateConsolidateAccountService));

        this.parmMethodName(methodStr(UpdateConsolidateAccountService, processOperation));

        this.parmDialogCaption("Update consolidate main account");

        // this.parmExecutionMode(SysOperationExecutionMode::ScheduledBatch);

    }


    public ClassDescription caption()

    {

        return "Update consolidate main account";

    }


    public static void main(Args args)

    {

        UpdateConsolidateAccountController controller = new UpdateConsolidateAccountController();

        controller.parmInBatch(true);

        controller.parmShowDialog(true);

        controller.startOperation();

    }

}

How to update column Based on joins in sql

 How to update column Based on joins in sql :-


UPDATE GeneralJournalAccountEntry

SET IS_ConsolidationMainAccount = '',

 IS_ConsolidateAccountName = ''

FROM GeneralJournalAccountEntry AS GJAE

 JOIN GeneralJournalEntry AS GJE

    ON GJE.RecId = GJAE.GeneralJournalEntry

WHERE GJE.SubledgerVoucherDataAreaId = 'VN06'

and GJE.ACCOUNTINGDATE > '2025-01-01'

Tuesday, September 2, 2025

How to Retrieve the Purchase Order Number in the LedgerTransAccount Form using X++ in D365 Finance & Operations

 How to Retrieve the Purchase Order Number in the LedgerTransAccount Form using X++ in D365 Finance & Operations

[ExtensionOf(tableStr(GeneralJournalEntry ))]

internal final class GeneralJournalEntryTable_Extension

{

 public display Name Ponumber()

    {

        Name                    ret;  

        VendInvoiceJour         VendInvoiceJour;

        VendTrans               VendTrans;

        VENDPACKINGSLIPVERSION  VENDPACKINGSLIPVERSION;

        VENDPACKINGSLIPJOUR     VENDPACKINGSLIPJOUR;


        select VendTrans

            where VendTrans.Voucher == this.SubledgerVoucher;


        select VendInvoiceJour where VendInvoiceJour.LedgerVoucher ==VendTrans.Voucher

            &&  VendInvoiceJour.InvoiceAccount ==VendTrans.AccountNum

            &&  VendInvoiceJour.InvoiceDate ==VendTrans.TransDate;

        if(VendInvoiceJour)

        {

            ret = VendInvoiceJour.PurchId;

        }

        

        SELECT VENDPACKINGSLIPJOUR FROM VENDPACKINGSLIPVERSION

            WHERE VENDPACKINGSLIPVERSION.LEDGERVOUCHER ==this.SubledgerVoucher;


        SELECT PACKINGSLIPId FROM VENDPACKINGSLIPJOUR

            WHERE VENDPACKINGSLIPJOUR.RECID == VENDPACKINGSLIPVERSION.VENDPACKINGSLIPJOUR;

        if(VENDPACKINGSLIPJOUR)

        {

            ret = VENDPACKINGSLIPJOUr.purchid;

        }


        return ret;

    }

}

workflow auto approval code in X++

 auto approval code:-       WorkflowWorkItemTable           WorkflowWorkItemTable;       WorkflowTrackingStatusTable     WorkflowTrackingSta...