0
votes

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.

2
decimal _taxPercent = 20.0; with subsequent suitable rounding applied....Mitch Wheat

2 Answers

2
votes

You could run into issues when there's no manual discount for example. Have you tried to step debug the code to see where if it crashes? You will also run into issues on an update since only the fields that are changed are in the property bag, there you also need to check the pre image.

0
votes

Ok folks, I've got a answer, sort of - but I'll post a new question for the next bit. With the help of this video (https://www.youtube.com/watch?v=54Zibk9v338) I have a working plugin - that calculates the tax field on the quotedetail entity.

I think what was getting me is that when you add a new product to a quote, the create message fires and adds the item to the form, then an update message applies the values. I was working on the notion that there was no Update message as I wasn't updating a form...

What I needed was a step that fired on the Create message to first set the variables like the Tax Percentage (20) and initialize the variables for the other fields, but then a second step that fired on the Update message to fetch the values and set the tax field.

What I have now is a tax field that calculates, but doesn't update if I change the manual discount amount field. It does if I change the amount field which is odd as the code is the same for both fields....but I'll post a new question for this.

Man my head hurts now