Question Status

Unanswered
Mark Pitts asked a question on 10 Dec 2009 3:22 PM

In addition to updating the opportunity entity, I also want to be to perform an update an attribute on the related account entity.

 

1.With current opportunity form opened, click  Actions, Opportunity Close.

2.I set the status to WIN.

3.This should trigger an update on an attribute on the account.

4.This should also trigger certain fields on the opportunity to become required.

 QN: What is the technique to perform updates against both Account and Opportunity.

Thanks in advance.

Reply
Inogic responded on 10 Dec 2009 7:49 PM

Hi Mark,

You need to trap the Pre/Post events of the Opportunity using the Win Plugin message.

In the Pre-event you can test for the required Opportunity attributes and if these are not filled in yet stop the Opportunity from being closed as Won.

In the Post Event, you would get the Opportunity id that was being closed as Won and from that read the account associated with it and update it accordingly.

You need to note that once an Opportunity has been closed, you cannot update any attribute of the opportunity.

You need to write Plugins to achieve the desired process flow.

HTH

Sam

Inogic

Innovative Logic  

Web: www.inogic.com

Blog: http://www.inogic.com/blog

twitter: @inogic

Reply
Jhelumi786 responded on 4 Jan 2010 8:08 AM

Hi Sam,

Could you please post some sample code showing the above. I'm interested to know:-

1) How to hold of associated account entity (Lookup field on Opportunity) and update its attribute (RelationshipType = Customer)

2) How to create a relationship between the account and opportunity so that the Opportunity appears in the "Opportunities" view of the account as well.

Thanks in advance

 Jhelumi786 

 

 

Reply
Mark Pitts responded on 4 Jan 2010 8:53 AM

You'll need to use the RegisterPluginTool to create the pre and  post events.

ValidateOpportunityWinPre.cs

         public void Execute(IPluginExecutionContext context)
        {
            // Verify we have a dynamic entity
            if (context.InputParameters.Properties.Contains("OpportunityClose")
                    && context.InputParameters.Properties["OpportunityClose"] is DynamicEntity)
            {
                // Since the opportunityid is not passed with the "Win" messsage,
                // we will retrieve the opportunityid from the child opportunityclose entity
                DynamicEntity oppClose =
                ((DynamicEntity)context.InputParameters.Properties["opportunityclose"]);

                // Verify that we are working with an opportunityclose record
                if (oppClose.Name == EntityName.opportunityclose.ToString())
                {
                    Guid opportunityId = ((Lookup)oppClose.Properties["opportunityid"]).Value;

                    ICrmService service = context.CreateCrmService(false);

                    // Retrieve the project start date from the opportunity checking if it has a value
                    bool validBidStatus = ValidateBidStatus(service, opportunityId);
                    if (!validBidStatus)
                    {
                        // Throw an error, because the project start date didn't have a value prior to closing the opportunity
                        throw new InvalidPluginExecutionException(
                            "Please make sure the opportunity bid status is either 'Decision Due' or 'Pending Sale'.");
                    }

                    // Retrieve the project start date from the opportunity checking if it has a value
                    bool hasRequiredFields = ValidateRequiredFields(service, opportunityId);
                    if (!hasRequiredFields)
                    {
                        // Throw an error, because the project start date didn't have a value prior to closing the opportunity
                        throw new InvalidPluginExecutionException(
                            "Please make sure all required fields are filled in before closing this opportunity. All required fields are labeled with  * when the opportunity is in a Decision Due bid status.");
                    }
                }
            }

 

UpdateRelationshipOpportunityWinPost.cs

        public void Execute(IPluginExecutionContext context)
        {

            // Verify we have a dynamic entity
            if (context.InputParameters.Properties.Contains("OpportunityClose")
                    && context.InputParameters.Properties["OpportunityClose"] is DynamicEntity)
            {
                // Since the opportunityid is not passed with the "Win" messsage,
                // we will retrieve the opportunityid from the child opportunityclose entity
                DynamicEntity oppClose = 
                ((DynamicEntity) context.InputParameters.Properties["opportunityclose"]) ;

                // Verify that we are working with an opportunityclose record
                if (oppClose.Name == EntityName.opportunityclose.ToString())
                {
                    Guid opportunityId = ((Lookup)oppClose.Properties["opportunityid"] ).Value;

                    ICrmService service = context. CreateCrmService(false);

                    // Retrieve the project start date from the opportunity checking if it has a value
                    bool validUpdate = UpdateAccount(service, opportunityId) ;
                    if (!validUpdate)
                    {
                        // Throw an error, because the project start date didn't have a value prior to closing the opportunity
                        throw new InvalidPluginExecutionException("Relationship not successfully updated.");
                    }
                }
            }
        }

 

        private bool UpdateAccount(ICrmService service, Guid opportunityId)
        {
            ColumnSet cols = new ColumnSet();
            cols.AddColumns(new string[] { "customerid" });

            TargetRetrieveDynamic targetRetrieve = new TargetRetrieveDynamic();
           
            targetRetrieve.EntityName = "opportunity";
            targetRetrieve.EntityId = opportunityId;

            RetrieveRequest retrieve = new RetrieveRequest();
            retrieve.Target = targetRetrieve;
            retrieve.ColumnSet = cols;
            retrieve.ReturnDynamicEntities = true;

            RetrieveResponse retrieved = (RetrieveResponse)service.Execute(retrieve);
            DynamicEntity entity = (DynamicEntity)retrieved.BusinessEntity;
            // if new_projectstartdate is null then it won't exist in the properties collection
            if (entity.Properties.Contains("customerid"))
            {
                Guid regardingId = ((Customer)entity.Properties["customerid"]).Value;
                // Retrieve the Account's target field
                TargetRetrieveAccount target = new TargetRetrieveAccount();
                target.EntityId = regardingId;

                RetrieveRequest getAccount = new RetrieveRequest();
                getAccount.ReturnDynamicEntities = true;

                getAccount.Target = target;
                getAccount.ColumnSet = new AllColumns();

                // Get the account

                RetrieveResponse retrievedAccount = (RetrieveResponse)service.Execute(getAccount);
                DynamicEntity regardingAccount = (DynamicEntity)retrievedAccount.BusinessEntity;
                // If the "Total number of call" exists, update them ,otherwise set it
                if (regardingAccount.Properties.Contains("customertypecode"))
                {
                    ((Picklist)regardingAccount.Properties["customertypecode"]).Value = 3;
                        service.Update(regardingAccount);
                }
               
            }
            return true;
        }
 

Reply
Jhelumi786 responded on 5 Jan 2010 8:07 AM

Hi Mark,

Thanks for sharing the code. I have managed to amend and build the plugin with my changes but I'm not sure about the  Registration tool. As this is my first plugin I have no idea what these fields should be. Just to make sure that the following fields are filled in correctly (as they work perfectly for me) could you please confirm they r OK.

Message:               Win

Primary Entity:        Opportunity

Secondary Entity:

Filtering Attributes:  All Attributes

Execution Order:       1

Evemting Pipeline Stage of Execution (Pre Stage/Post stage) :         Post Stage

Triggering Pipeline (Parent / Child) :              Parent

 

Thanks for ur help once again and a prompt response would be much appreciated.

 

Regards

Jhelumi786

Reply
Mark Pitts responded on 5 Jan 2010 12:50 PM

Everything looks correct. My validation plugin acts on the pre-event. And my account update plug-in acts on the post-event. So, there are 2 separate registration entries.

Also, for testing/debugging purposes, it's easiest to copy the assembly '.dll' as well as '.pdb' in the crm server/bin/assembly folder.

Cheers!

Reply
Sugianto Sugianto responded on 10 Jan 2010 11:09 PM
Interesting, mind if i join? one question : how come " server/bin/assembly " folder is empty ? thank you
Reply
Mark Pitts responded on 11 Jan 2010 2:57 AM

Please check out this msdn page for more information

(http://msdn.microsoft.com/en-us/library/cc151088.aspx)

Cheers!

Reply
Amit Kasundra responded on 27 Feb 2012 11:29 PM

Hi All,

I want to trap the Opportunity Win message via plugin and want to execute one console application code of VS 2010 when Opportunity close as WON.

So, my registration tool fields should be same as Jhelumi786 posted here CORRECT IF I AM WRONG. but i dont know what are the changes needed to be done on the code that Mark posted here.

 it will be great If anyone can post some sample code as per my requirement.

Thanks in advance..

Reply