Get the Next Birthday

The following sample workflow activity returns the next birthday. Use this in a workflow that sends a birthday greeting to a customer. Note that this uses dynamic entity rather than strong types as is recommended for workflows and plug-ins.



using System;
using System.Collections;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Reflection;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;

namespace SampleWorkflows
{
///
/// Activity will return the next upcoming birthday that has just passed
///
/// If this year's birthday has not yet occurred, it will return this year's birthday.
/// Otherwise, it will return the birthday for next year.
///
/// A workflow can time-out when on this date.
///

[CrmWorkflowActivity("Get the Next Birthday", "Release Scenarios")]
[PersistOnClose]
public partial class UpdateNextBirthday : SequenceActivity
{
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
IWorkflowContext context = contextService.Context;

//Create a CRM Service.
ICrmService crmService = context.CreateCrmService();

//Retrieve the contact ID.
Guid contactId = ((Lookup)base.GetValue(ContactProperty)).Value;

//Retrieve the entity to determine what the birth date is.
//Retrieve the Contact Entity
DynamicEntity contactEntity;
{
//Create the target.
TargetRetrieveDynamic retrieveTarget = new TargetRetrieveDynamic();
retrieveTarget.EntityId = contactId;
retrieveTarget.EntityName = EntityName.contact.ToString();

//Create a request.
RetrieveRequest retrieveRequest = new RetrieveRequest();
retrieveRequest.ColumnSet = new ColumnSet(new string[] {"birthdate" });
retrieveRequest.ReturnDynamicEntities = true;
retrieveRequest.Target = retrieveTarget;

//Execute the request.
RetrieveResponse retrieveResponse = (RetrieveResponse)crmService.Execute(retrieveRequest);

//Retrieve the Loan Application Entity.
contactEntity = retrieveResponse.BusinessEntity as DynamicEntity;
}

//Check to see if the current birthday is set. We don't want the activity to fail if the birth date is not set.
CrmDateTime contactBirthDate = (CrmDateTime)contactEntity["birthdate"];
if (contactBirthDate == null || (contactBirthDate.UniversalTime == null))
{
//Complete the execution of the activity.
return base.Execute(executionContext);
}

//Calculate the next birth date. Encapsulate it in a method so that the method can be used in the test case for verification purposes.
DateTime nextBirthdate = CalculateNextBirthday(contactBirthDate.UniversalTime);

//Update the next birthday field on the entity.
DynamicEntity updateEntity = new DynamicEntity(EntityName.contact.ToString());
updateEntity["contactid"] = new Key(contactId);
updateEntity["new_nextbirthday"] = CrmDateTime.FromUniversal(nextBirthdate);

crmService.Update(updateEntity);

CompositeActivity parentActivity = this.Parent;
while (parentActivity.Parent != null)
{
parentActivity = parentActivity.Parent;
}

context.PopulateEntitiesFrom((CrmWorkflow)parentActivity, "primaryEntity");

//Allow the base class to continue the execution.
return ActivityExecutionStatus.Closed;
}

//Define the variables.
public static DependencyProperty ContactProperty = DependencyProperty.Register("Contact", typeof(Lookup), typeof(UpdateNextBirthday));

//Define the properties.
[CrmInput("Update Next Birthdate for")]
[ValidationOption(ValidationOption.Required)]
[CrmReferenceTarget("contact")]
public Lookup Contact
{
get
{
return (Lookup)base.GetValue(ContactProperty);
}
set
{
//Validate the argument.
if (value == null || (value.IsNullSpecified && value.IsNull))
{
throw new InvalidPluginExecutionException("Contact Lookup cannot be null or have IsNullSpecified = true");
}
else if (value.type != null && value.type != "contact")
{
throw new InvalidPluginExecutionException("Contact Lookup must be a contact entity");
}
else if (value.Value == Guid.Empty)
{
throw new InvalidPluginExecutionException("Contact Lookup must contain a valid Guid");
}

base.SetValue(ContactProperty, value);
}
}

private DateTime CalculateNextBirthday(DateTime birthdate)
{
DateTime nextBirthday = new DateTime(birthdate.Year, birthdate.Month, birthdate.Day);

//Check to see if this birthday occurred in a leap year.
bool leapYearAdjust = false;
if (nextBirthday.Month == 2 && nextBirthday.Day == 29)
{
//Verify that this year was a leap year.
if (DateTime.IsLeapYear(nextBirthday.Year))
{
//Check to see if the current year is a leap year.
if (!DateTime.IsLeapYear(DateTime.Now.Year))
{
//Push the date to March 1st so that the date arithmetic will function correctly.
nextBirthday = nextBirthday.AddDays(1);
leapYearAdjust = true;
}
}
else
{
throw new InvalidPluginExecutionException("Invalid Birthdate specified", new ArgumentException("Birthdate"));
}
}

//Calculate the year difference.
nextBirthday = nextBirthday.AddYears(DateTime.Now.Year - nextBirthday.Year);

//Check to see if the date was adjusted.
if (leapYearAdjust && DateTime.IsLeapYear(nextBirthday.Year))
{
nextBirthday = nextBirthday.AddDays(-1);
}

return nextBirthday;
}
}
}