A problem that has been plaguing me for a while is the fact that Microsoft CRM Dynamics does not calculate tax automatically. CRM insists on having the user type in the amount of tax manually. Firstly, it's a pain to work out 20% of a decimal number (2 d.p), secondly, and most importantly, if our sales guys have to open up each quote product individually, then calculate the tax, type that in and then save the record, they'll fail miserably at selling stuff. I'm trying to develop a plugin that fires on the Create or Update message, Pre-Operation of a Quote Product (Entity Logical Name = quotedetail) that calculates the "tax" field, using the Amount ["baseamount"] and any Manual Discount ["manualdiscountamount"].
The basic math is tax = (baseamount - manualdiscountamount) / 100 * 20
The trouble I seem to be having is that if the variable _tax is defined as a direct decimal number, say 30, the value is passed to the field correctly but if I try to set the _tax value using the values of another field, the value remains as 0.00. Heres my code:
public void Execute(IServiceProvider serviceProvider)
{
// Sets the context for the plugin environment
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Required for tracing
ITracingService trace = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Create empty entity variable
Entity entity = null;
// Check if the InputParameters property contains a target
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the InputParameters
entity = (Entity)context.InputParameters["Target"];
// If message type is not Create OR Update AND it is not a Quote Product, exit gracefully
if (context.MessageName != "Create"
|| context.MessageName != "Update"
&& context.PrimaryEntityName != "quotedetail")
{
return;
}
}
else
{
return;
}
try
{
// Used to access Data and Metadata for the platform
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Cast the 2 entity methods to access properties from entity retrived by context
QuoteDetail currentEntity = entity.ToEntity<QuoteDetail>();
// Set the variables
int _taxPercent = 20;
decimal _amount = currentEntity.BaseAmount.Value;
decimal _manualDiscount = currentEntity.ManualDiscountAmount.Value;
decimal _preTaxAmount = _amount - _manualDiscount;
// Do the math and store in _tax
decimal _tax = _preTaxAmount / 100 * taxPercent;
// Set Tax field to value stored in _tax
currentEntity.Tax = new Money(_tax);
}
catch (FaultException<OrganizationServiceFault> ex)
{
trace.Trace("Exception: " + ex.Message + " " + ex.StackTrace);
throw new InvalidPluginExecutionException("An error occured in the plugin.", ex);
}
}
I believe my problem is that during the Create of the Quote Product, the .Values for the decimal variables have not been passed into the context yet as this is happening pre-operation.
Does anyone have any clues as to how I might accomplish this task? I'm amazed that MS left this out of CRM.
This seems like a big ask.
Edit 1: The correct syntax for the variables is:
Money _amount = new Money(currentEntity.BaseAmount.Value);
not
decimal _amount = currentEntity.BaseAmount.Value;
this is because they are Money fields, however, it seems the value of BaseAmount is 0.00 during the Pre-Operation of the Create message
Edit 2: Last night debugged my plugin using the ITracingService. I found that the quotedetail entity was also firing an update message after the create message. What i still cant work out is when the field data is populated, i.e. when the Price Per Unit field actually receives its data passed in from the Produt entity. I have got this working. My process involved setting field values and nullable object values during a PreCreate message, fetching a PreUpdate image and passing this to a PreUpdate message that fires right after the create message.