Friday, June 15, 2012

Cancel Workflow job programmatically - CRM v.4

How many times you had to created a workflow on some date like Due date which keeps changing as per client's request. While this may sound simple in business, on CRM you have a workflow that may be waiting till this date and send a reminder exactly a week before.

So you need to keep calling this workflow every time the date is updated, to make the matters more complicated, all the previous jobs that had initiated due to past modification will keep running and chasing that date which is never going to occur. What you do now, manually cancel those to save system resources and stop the never ending system jobs.

There is a way to do it through SDK, in my case I call this function as a custom workflow activity in the first step of the workflow which Cancels any previous jobs of this workflow.

  #region Cancel My WFs

            QueryExpression qe = new QueryExpression();
            qe.EntityName = EntityName.asyncoperation.ToString();
            ColumnSet cs = new ColumnSet();
            cs.Attributes = new string[] { "name", "regardingobjectid", "createdon","statuscode","statecode" };
           
            FilterExpression fe = new FilterExpression();
            fe.FilterOperator = LogicalOperator.And;

            ConditionExpression ce1 = new ConditionExpression();
            ce1.Operator = ConditionOperator.Equal;
            ce1.AttributeName = "regardingobjectid"; // Your record id
            ce1.Values = new object[] { new Guid("EE87FB7E-6C1F-E111-AF92-0050569F0AE2") };

            ConditionExpression ce2 = new ConditionExpression();
            ce2.Operator = ConditionOperator.Equal;
            ce2.AttributeName = "name"; // GUID of the Waiting Workflow: WF_InDeal_NextEndofTermNotificationDate_Update
            ce2.Values = new object[] { "Your_WF_Name" };

            ConditionExpression ce3 = new ConditionExpression();
            ce3.Operator = ConditionOperator.NotEqual;
            ce3.AttributeName = "statuscode"; // GUID of the Waiting Workflow: WF_InDeal_NextEndofTermNotificationDate_Update
            Status CancelledStatus = new Status(); CancelledStatus.Value = 32;
            ce3.Values = new object[] { CancelledStatus };

            fe.Conditions = new ConditionExpression[] { ce1,ce2};
            fe.FilterOperator = LogicalOperator.And;
            //fe.AddCondition(ce1);
            //fe.AddCondition(ce2);

            qe.ColumnSet = cs;
            qe.Criteria = fe;

            req = new RetrieveMultipleRequest();
            req.ReturnDynamicEntities = true;
            req.Query = qe;
            RetrieveMultipleResponse resp = null;
            resp = (RetrieveMultipleResponse)serv.Execute(req);
            if (resp.BusinessEntityCollection.BusinessEntities.Length  > 0)
            {
                BusinessEntityCollection bec = resp.BusinessEntityCollection;
                asyncoperation asyncOperation = null;
                DynamicEntity dynamicEntity = null;
                TargetUpdateAsyncOperation targetUpdateAsyncOperation = null;
               
                string Status = "";
                for (int i = 0; i < bec.BusinessEntities.Length-1 ; i++)
                {
                    Status = ((UpdateProductBasePrice.crmService.StatusProperty)(((UpdateProductBasePrice.crmService.DynamicEntity)(bec.BusinessEntities[i])).Properties[4])).Value.name;
                    if (!Status.Equals("Canceled"))
                    {
                        asyncOperation = new asyncoperation();
                        dynamicEntity = (DynamicEntity)bec.BusinessEntities[i];
                        asyncOperation.asyncoperationid = new Key();
                        asyncOperation.asyncoperationid.Value = new Guid(((UpdateProductBasePrice.crmService.KeyProperty)(dynamicEntity.Properties[5])).Value.Value.ToString());
                        asyncOperation.statuscode = new Status();
                        asyncOperation.statuscode.Value = 32;
                        asyncOperation.statecode = new AsyncOperationStateInfo();
                        asyncOperation.statecode.Value = AsyncOperationState.Completed;

                        targetUpdateAsyncOperation = new TargetUpdateAsyncOperation();
                        targetUpdateAsyncOperation.AsyncOperation = asyncOperation;

                        UpdateRequest updateAsync = new UpdateRequest();
                        updateAsync.Target = targetUpdateAsyncOperation;

                        try
                        {
                            serv.Execute(updateAsync);
                        }
                        catch (System.Web.Services.Protocols.SoapException soapEx)
                        {
                            continue;
                        }
                    }
                }

            }
            return;
            #endregion