Wednesday, January 31, 2018

Workflow Batch Error: "Failed to find workflow"

Resolution:

Note: Before running in any AX environment, Take backup of table and data from SQL for the table(SYSWORKFLOWMESSAGETABLE)

Code snippet:

static void San_WkfjobError(Args _args)
{
    SysWorkflowMessageTable sysWorkflowMessageTable;
    SysWorkflowTable sysWorkflowTable;
    ;
    ttsBegin;
    while Select forupdate sysWorkflowMessageTable
        Where sysWorkflowMessageTable.MESSAGELIFECYCLESTATE == 1 
            && sysWorkflowMessageTable.ROOTCORRELATIONID
        notexists join sysWorkflowTable
            where sysWorkflowTable.RootCorrelationId == sysWorkflowMessageTable.RootCorrelationId
    {
        info(strFmt("%1,%2",sysWorkflowMessageTable.RecId,sysWorkflowMessageTable.AssignedUser));
        sysWorkflowMessageTable.MESSAGELIFECYCLESTATE = 2;
        sysWorkflowMessageTable.update();
    }
    ttsCommit;
}

Failed to log in Dynamics AX - workflow error

Check users access  in Workflowdocument class

Get List of user doesn't have proper access for class-SysWorkflowDocument

Create New class

public static server void main(Args _args)
{
    container   result, args;
    UserInfo    UserInfo;

    while select id from UserInfo
    {
        try
        {
            new RunAsPermission(UserInfo.id).assert();
            result = runAs(UserInfo.id, classNum(SysWorkflowDocument), staticMethodStr(SysWorkflowDocument, assertAsUser), args);
            CodeAccessPermission::revertAssert();
        }
        catch
        {
            CodeAccessPermission::revertAssert();
            info(UserInfo.id);
        }
    }
}

Tuesday, January 30, 2018

Delete a model in Dynamics 365 for FO

Reference & Source Content link:

Command -> ModelUtil.exe -delete -metadatastorepath="K:\AOSService\PackagesLocalDirectory" -modelname="Main2"

Directory: K:\AOSService\PackagesLocalDirectory\Bin
   
      Solutions:

1.    Model belongs to its own package 
(For example: An extension package with no other models in the package):
a.      Stop the following services: The AOS web service and the Batch Management Service
b.     Delete the package folder C:\AOSService\PackagesLocalDirectory\<your model>
c.      Restart the services from step 1
d.     If Visual Studio is running, refresh your models (Visual Studio > Dynamics 365 > Model management > Refresh models)
e.      In Visual Studio, perform a full database synchronization (Visual Studio > Dynamics 365 > Synchronize database...)

2.    Model belongs to a package with multiple models 
(For example, <your model> overlays Application Suite):
a.      Stop the following services: The AOS web service and the Batch Management Service
b.     Delete the model folder C:\AOSService\PackagesLocalDirectory<PackageName>\<your model> (In this example PackageName=ApplicationSuite)
c.      Restart the services from step 1
d.     In Visual Studio, refresh your models (Visual Studio > Dynamics 365 > Model management > Refresh models)
e.      In Visual Studio, build the package that the deleted models belonged to (Visual Studio > Dynamics 365 > Build models...)
f.       In Visual Studio, perform a full database synchronization (Visual Studio > Dynamics 365 > Synchronize database...)


Sending message to all Online users in DAX 365 FO


Steps:
Step 1: Login into your official LCS account where DAX 365 FO enviornment deployed
Step 2: Under Environment section ->> select your environment ->> Click on maintain option
->>   Select Message online users
Step 3:  Select any one of option from below list
                           ->> Broadcast a new message (Posting a new message)
                           ->> Cancel message (To cancel existing posted message)
            Step 4: 
->>Select Broadcast a new message, you have to provide start date time and when this operation will begin or massage valid end date time
->> Click on Post button
Step 5: When a user will login into environment, they must be get this message. Once successfully posted
Step 6: Now In case if you want to postpone or cancel the activity
->> Select cancel message mentioned in Step 3
->> Select the message which you want to cancel message and click delete

Remove RecId Suspension in X++


    systemSequence sequence = new systemSequence();
    sequence.removeRecIdSuspension(tableId);

Recover workflow to initial draft state for the document data in ax 2012

static void RecoverWorkflow_VendInvoice(Args _args)
{
    VendInvoiceInfoTable            vendInfoTable;
    VendInvoiceInfoLine             vendInfoLine;

    WorkflowTrackingStatusTable     workflowTrackingStatusTable, workflowTrackingStatusTable_forDelete;
    WorkflowTrackingTable           workflowTrackingTable;
    WorkflowTrackingWorkItem        workflowTrackingWorkItem;
    WorkflowWorkItemTable           workflowWorkItemTable_forDelete;

    WorkflowCorrelationId           rootCorrelationId;
    SysWorkflowTable                sysWorkflowTable_forDelete;

    Dialog                          dialog;
    DialogField                     vendInvoiceField;
    DialogField                     vendInvoiceWFStatus;
    Str 30                          vendInvoiceId;
    Counter                         totalLines;

    dialog              = new Dialog("Delete Workflow history and reset vend invoice status to Draft");
    vendInvoiceField     = dialog.addField(extendedTypeStr(Name));
    vendInvoiceWFStatus = dialog.addField(enumStr(WorkflowTrackingStatus));
    dialog.run();

    if (dialog.closedOk())
    {
        vendInvoiceId = vendInvoiceField.value();

        if (!vendInvoiceId)
            return;

        if (Box::yesNo(strFmt("Do you want to reset vend invoice number %1 in %2 LE?", vendInvoiceId, curext()), DialogButton::Yes == DialogButton::Yes))
        {
            ttsbegin;

            select forUpdate vendInfoTable
                where vendInfoTable.num == vendInvoiceId && vendInfoTable.num != "";

            select firstOnly workflowTrackingStatusTable
                where workflowTrackingStatusTable.ContextCompanyId  == vendInfoTable.dataAreaId &&
                      workflowTrackingStatusTable.ContextTableId    == vendInfoTable.TableId &&
                      workflowTrackingStatusTable.ContextRecId      == vendInfoTable.RecId &&
                      workflowTrackingStatusTable.TrackingStatus    == vendInvoiceWFStatus.value();

            if (vendInfoTable.RequestStatus == VendInvoiceRequestStatus::InReview
                    && workflowTrackingStatusTable)
            {
                rootCorrelationId = workflowTrackingStatusTable.RootCorrelationId;

                //delete work items
                while select workflowTrackingStatusTable
                    where workflowTrackingStatusTable.RootCorrelationId == rootCorrelationId &&
                          workflowTrackingStatusTable.ContextCompanyId  == vendInfoTable.dataAreaId &&
                          (workflowTrackingStatusTable.ContextTableId == tableNum(VendInvoiceInfoTable)
                            || workflowTrackingStatusTable.ContextTableId == tableNum(VendInvoiceInfoLine))
                    join workflowTrackingTable
                        where workflowTrackingTable.WorkflowTrackingStatusTable == workflowTrackingStatusTable.RecId
                        join workflowTrackingWorkItem
                            where workflowTrackingWorkItem.WorkflowTrackingTable == workflowTrackingTable.RecId
                {
                    while select forUpdate workflowWorkItemTable_forDelete
                        where workflowWorkItemTable_forDelete.RecId == workflowTrackingWorkItem.WorkflowWorkItemTable &&
                              workflowWorkItemTable_forDelete.Id    == workflowTrackingWorkItem.WorkItemId
                    {
                        info(strFmt("WorkflowWorkItemTable record ID %1 is deleted", workflowWorkItemTable_forDelete.RecId));
                        workflowWorkItemTable_forDelete.delete();
                    }
                }

                //delete tracking status
                while select forUpdate workflowTrackingStatusTable_forDelete
                    where workflowTrackingStatusTable_forDelete.RootCorrelationId == rootCorrelationId &&
                          workflowTrackingStatusTable_forDelete.ContextCompanyId  == vendInfoTable.dataAreaId &&
                          (workflowTrackingStatusTable_forDelete.ContextTableId == tableNum(VendInvoiceInfoTable)
                            || workflowTrackingStatusTable_forDelete.ContextTableId == tableNum(VendInvoiceInfoLine))
                {
                    info(strFmt("WorkflowTrackingStatusTable record ID %1 instance number %2 is deleted", workflowTrackingStatusTable_forDelete.RecId, workflowTrackingStatusTable_forDelete.InstanceNumber));
                    workflowTrackingStatusTable_forDelete.delete();
                }

                //delete sysWorkflowTable
                while select forUpdate sysWorkflowTable_forDelete
                    where sysWorkflowTable_forDelete.RootCorrelationId == rootCorrelationId &&
                          sysWorkflowTable_forDelete.ContextCompanyId  == vendInfoTable.dataAreaId    &&
                          (sysWorkflowTable_forDelete.ContextTableId == tableNum(VendInvoiceInfoTable)
                            || sysWorkflowTable_forDelete.ContextTableId == tableNum(VendInvoiceInfoLine))
                {
                    info(strFmt("SysWorkflowTable record ID %1 is deleted", sysWorkflowTable_forDelete.RecId));
                    sysWorkflowTable_forDelete.delete();
                }

                //reset status to Draft
                vendInfoTable.RequestStatus = VendInvoiceRequestStatus::Draft;
                vendInfoTable.doUpdate();

                while select forUpdate vendInfoLine
                    where vendInfoLine.TableRefId == vendInfoTable.TableRefId
                        && vendInfoLine.ParmId == vendInfoTable.ParmId
                {
                    vendInfoLine.RequestStatus = VendInvoiceRequestStatus::Draft;
                    vendInfoLine.doUpdate();
                    totalLines++;
                }

                info(strFmt("Workflow instance is deleted."));
                info(strFmt("Vend invoice number %1 has been reset to Draft.", vendInvoiceId));
                info(strFmt("Total lines that reset to Draft: %1.", totalLines));
            }
            else
            {
                info(strFmt("Nothing to update. The approval status is not %1 status or there is no existing workflow history.",enum2str(vendInvoiceWFStatus.value())));
            }

            ttsCommit;

        }
    }

}

Wednesday, January 17, 2018

Change SQL DB from SUSPECT to NORMAL mode

ALTER DATABASE  MicrosoftDynamicsAX  SET  EMERGENCY

DBCC CHECKDB('MicrosoftDynamicsAX')

ALTER DATABASE MicrosoftDynamicsAX SET SINGLE_USER WITH ROLLBACK IMMEDIATE

--Take DB backup,,before running below script.

DBCC CHECKDB (MicrosoftDynamicsAX, REPAIR_ALLOW_DATA_LOSS)


ALTER DATABASE MicrosoftDynamicsAX SET MULTI_USER

Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...