locked
Update Total on Parent record on creation, updation or deletion of child record RRS feed

  • Question

  • Hi, I have a parent and child entity as follows:

    Parent: Contact

    Child: Course (Custom Entity)

    Relationship is N:1 Contact could subscribe to more than one Courses. The course entity has an attribute Fees (datatype is money). On Contact entity there is a custom attribute of TotalFees.

    The TotalFees attribute on Contacts entity should display the total fees of all the courese subscribed by the Contact. e.g.

    In a Gym the Contact has subscribed to Yoga (Fees 100) and Aerobics (Fees 200). The total of fees should be displayed and updated in the TotalFees attribute of the Contact entity whenever a record in Course entity is created, updated or deleted.

    Please guide me how this can be accomplished through plug-in under the following cases.

    Record is Created: How to know what is the contactid for which the TotalFees will be updated.

    Update and Delete: How to update the TotalFees value from the plug-in. How to know the contactID from plug-in

    For which entity the plug-in should be registered and for what events and stages e.g. Pre-create, post-create of contact/course. etc.

    Regards

     

    HSG.

    Friday, January 21, 2011 11:27 AM

Answers

  • Hi,

    Creation :

     You should be able to use a pre-create event and search for the ID of the parent contact:

                            if (entity.Properties.Contains("new_contactcourseid")) //Ensure the course has not been created without a contact.
                                       Lookup x= (Lookup)PreEntity.Properties["new_contactcourseid"];

    This will provide the ID of the parent contact.

    Retrieve this contact record including the current TotalFees, calculate the new TotalFees

    To update the parent contact :

                    PropertyCollection pc = new PropertyCollection();

                    pc.Add(CrmTypes.CreateKeyProperty("tsm_tradespendplanningunitid", new Key(new Guid(x.Value))));
                    pc.Add(CrmTypes.CreatePicklistProperty("new_totalFees", CrmTypes.CreatePicklist((int)status)));

                    DynamicEntity entity = new DynamicEntity();
                    entity.Name = "tsm_tradespendplanningunit";
                    entity.Properties = pc;

                    ICrmService service = context.CreateCrmService(true);

                    service.Update(entity);  

    Update :

    This 'should' be performed (to maintain transactional integrity) as a pre-update event.


    Delete :

    The same logic applies as per update.

    Note, MS CRM 4.0 does not support transactions, so you may update the parent contact only for the 'course update' event to fail, which results in dirty data. In some cases like these, you may want to look at the following logic and using mostly pre-callouts.

    1. Update parent contact with new totals (set a flag to complete = false)

    2. If 1 succeeds, update course

    3. If 2 succeeds, update parent contact (set flag to complete = true)

    You should be able to see any parent contacts with 'dirty data' by viewing the 'complete' flag.

    You can use the PostCreate events, however the benefit of using a PreCreate is that it will fail completely if the parent contact could not be updated.

     

    Lastly, as the data in the course will always be correct, you should probably include a routine on the parent contact, to recalculate totals. This is similar to how invoicing works in MS CRM with the 'recalculate' button.

    Hope it helped.

     

     

     

     

     

     


    Karlo Swart Ver206
    Blog
    Friday, January 21, 2011 3:46 PM

All replies

  • Change field and entity names according to your envoirnment. You need to put this code onSave of child entity:-

    if ((crmForm.all.new_quantity.IsDirty) || (crmForm.all.new_rate.IsDirty))
    {
    if (window.opener!= null)
    {
    window.opener.location.reload();
    }
    }

    You need to put similar code onLoad of parent entity:-

    // #################
    // Update Totals

    // #################
    if (crmForm.FormType != 1) {
         var oId = crmForm.ObjectId;
        var oTotalAmount = 0;
        var oSumTotalAmount = 0;
        // alert(oId);
        var xml = "" +
    "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
    "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
    GenerateAuthenticationHeader() +
    " <soap:Body>" +
    " <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
    " <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
    " <q1:EntityName>new_purchaseorderdetail</q1:EntityName>" +
    " <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
    " <q1:Attributes>" +
    " <q1:Attribute>new_purchaseorderdetailid</q1:Attribute>" +
    " <q1:Attribute>new_totalamount</q1:Attribute>" +
    " <q1:Attribute>new_poid</q1:Attribute>" +
    " </q1:Attributes>" +
    " </q1:ColumnSet>" +
    " <q1:Distinct>false</q1:Distinct>" +
    " <q1:Criteria>" +
    " <q1:FilterOperator>And</q1:FilterOperator>" +
    " <q1:Conditions>" +
    " <q1:Condition>" +
    " <q1:AttributeName>new_poid</q1:AttributeName>" +
    " <q1:Operator>Equal</q1:Operator>" +
    " <q1:Values>" +
    " <q1:Value xsi:type=\"xsd:string\">" + oId + "</q1:Value>" +
    " </q1:Values>" +
    " </q1:Condition>" +
    " </q1:Conditions>" +
    " </q1:Criteria>" +
    " </query>" +
    " </RetrieveMultiple>" +
    " </soap:Body>" +
    "</soap:Envelope>";
        var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
        xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
        xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
        xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
        xmlHttpRequest.send(xml);
        var resultXml = xmlHttpRequest.responseXML.xml;
        //alert(resultXml );


        if (resultXml != null || resultXml != "") {
            var xmlDocument = new ActiveXObject("Microsoft.XMLDOM");
            var bLoaded = xmlDocument.loadXML(resultXml);
            if (bLoaded) {
                var businessEntities = xmlDocument.getElementsByTagName('BusinessEntity');

                for (i = 0; i < businessEntities.length; i++) {
                    try {
                        var oTotalAmount = businessEntities[i].selectSingleNode("./q1:new_totalamount").text;

                        oSumTotalAmount += parseFloat(oTotalAmount);
                        //alert(oDiscount);

                    }
                    catch (err)
    { }
                }

            }
        }
     
        crmForm.all.new_subtotal.DataValue = oSumTotalAmount;
        crmForm.all.new_vattotal.DataValue = oSumTotalAmount * TaxRate/100;
        crmForm.all.new_totalamount.DataValue = oSumTotalAmount + crmForm.all.new_vattotal.DataValue ;

       crmForm.all.new_subtotal.ForceSubmit = true;
        crmForm.all.new_vattotal.ForceSubmit = true;
        crmForm.all.new_totalamount.ForceSubmit = true;


    }


    Regards Faisal
    Friday, January 21, 2011 11:34 AM
  • Hi,

    Creation :

     You should be able to use a pre-create event and search for the ID of the parent contact:

                            if (entity.Properties.Contains("new_contactcourseid")) //Ensure the course has not been created without a contact.
                                       Lookup x= (Lookup)PreEntity.Properties["new_contactcourseid"];

    This will provide the ID of the parent contact.

    Retrieve this contact record including the current TotalFees, calculate the new TotalFees

    To update the parent contact :

                    PropertyCollection pc = new PropertyCollection();

                    pc.Add(CrmTypes.CreateKeyProperty("tsm_tradespendplanningunitid", new Key(new Guid(x.Value))));
                    pc.Add(CrmTypes.CreatePicklistProperty("new_totalFees", CrmTypes.CreatePicklist((int)status)));

                    DynamicEntity entity = new DynamicEntity();
                    entity.Name = "tsm_tradespendplanningunit";
                    entity.Properties = pc;

                    ICrmService service = context.CreateCrmService(true);

                    service.Update(entity);  

    Update :

    This 'should' be performed (to maintain transactional integrity) as a pre-update event.


    Delete :

    The same logic applies as per update.

    Note, MS CRM 4.0 does not support transactions, so you may update the parent contact only for the 'course update' event to fail, which results in dirty data. In some cases like these, you may want to look at the following logic and using mostly pre-callouts.

    1. Update parent contact with new totals (set a flag to complete = false)

    2. If 1 succeeds, update course

    3. If 2 succeeds, update parent contact (set flag to complete = true)

    You should be able to see any parent contacts with 'dirty data' by viewing the 'complete' flag.

    You can use the PostCreate events, however the benefit of using a PreCreate is that it will fail completely if the parent contact could not be updated.

     

    Lastly, as the data in the course will always be correct, you should probably include a routine on the parent contact, to recalculate totals. This is similar to how invoicing works in MS CRM with the 'recalculate' button.

    Hope it helped.

     

     

     

     

     

     


    Karlo Swart Ver206
    Blog
    Friday, January 21, 2011 3:46 PM