Hi Dave,
Just relax. I have the solution for it.
As per your requirement you are not using the full implementation of the contract. I mean you are just using contracts without contract line. Its OK.
As we know, there is a system job running everyday and expires contracts whose end date is passed. Once the status is getting expired you can not change anything on this.
So for your case you have to restrict the status change from draft to Expire.
For this you need to write a plugin for it which will run to restrict the status change.
the below code will be required for the plugin.
Important NOTE : Change the code accordingly.
Lets Say Plugin Name : RestrictAutoExpireContracts.cs
/// The class begins
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using System.Xml;
using System.ServiceModel;
using System.Web.Services.Protocols;
public class RestrictAutoExpireContracts : IPlugin
{
//Restrict OOB Auto Expire of contract and Contract
//Pre Operation
public void Execute(IServiceProvider serviceProvider)
{
try
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Get a reference to the organization service.
IOrganizationServiceFactory factory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
// Check the InputParameters for an EntityMoniker instance to work with; validate type
if (context.InputParameters.Contains("EntityMoniker") &&
context.InputParameters["EntityMoniker"] is EntityReference)
{
EntityReference contractInfo = (EntityReference)context.InputParameters["EntityMoniker"];
// Verify entity is a Contract instance
if (contractInfo.LogicalName != "contract")
throw new InvalidPluginExecutionException("Failure in ContractSetStateHandler: Not a Contract instance.");
if (!context.PreEntityImages.Contains("PreSetStateContract"))
throw new InvalidPluginExecutionException("Failure in ContractSetStateHandler: Missing PreSetStateContract image.");
if (!context.PreEntityImages["PreSetStateContract"].Attributes.Contains("statecode"))
throw new InvalidPluginExecutionException("Failure in ContractSetStateHandler: Missing state in context.");
Entity preSetStateContract = (Entity)context.PreEntityImages["PreSetStateContract"];
if (!preSetStateContract.Attributes.Contains("statecode"))
throw new InvalidPluginExecutionException("Failure in ContractSetStateHandler: Missing statecode in image.");
int oldStateCode = ((OptionSetValue)preSetStateContract.Attributes["statecode"]).Value;
int newStateCode = ((OptionSetValue)context.InputParameters["State"]).Value;
// Make sure we only care about a transition from Draft to Expired
if ((newStateCode != 0) && oldStateCode == 0)
throw new InvalidPluginExecutionException("Draft Contracts are not allowed to automatically change OOB state.");
}
else
throw new InvalidPluginExecutionException("Failure in ContractSetStateHandler: Expected EntityMoniker unavailable.");
}
catch (SoapException ex)
{
throw new Exception("Error from CRM service : " + ex.Message);
}
catch (Exception ex)
{
throw new Exception("Error from CRM service : " + ex.Message);
}
}
}
NOTE: After writing the plugin register the plugin with below option:
1. register the assembly in post operation of setstate message

2. add preimage for the setstate step with name : PreSetStateContract
3. add step for setstatedynamicEntity & Add preimage PreSetStateContract.

Now Your Work is Done. Now the contracts of your system will never be expired and at anytime you can edit the dates. Cheers. :)