Search code examples
javascriptc#typescriptdynamics-crm

How to prevent Dynamics CRM 2015 from creating an opportunity when a lead is qualified?


Requirements when clicking the Qualify button in the Lead entity form:

  • Do not create an Opportunity
  • Retain original CRM qualify-lead JavaScript
  • Detect duplicates and show duplicate detection form for leads
  • Redirect to contact, either merged or created version, when done

Solution

  • So Pawel Gradecki already posted how to prevent CRM from creating an Opportunity when a Lead is qualified. The tricky part is to make the UI/client refresh or redirect to the contact, as CRM does nothing if no Opportunity is created.

    Before we begin, Pawel pointed out that

    some code is not supported, so be careful during upgrades

    I don't have experience with any other versions than CRM 2015, but he writes that there are better ways to do this in CRM 2016, so upgrade if you can. This is a fix that's easy to implement now and easy to remove after you've upgraded.

    Add a JavaScript-resource and register it in the Lead form's OnSave event. The code below is in TypeScript. TypeScript-output (js-version) is at the end of this answer.

    function OnSave(executionContext: ExecutionContext | undefined) {
        let eventArgs = executionContext && executionContext.getEventArgs()
        if (!eventArgs || eventArgs.isDefaultPrevented() || eventArgs.getSaveMode() !== Xrm.SaveMode.qualify)
            return
    
        // Override the callback that's executed when the duplicate detection form is closed after selecting which contact to merge with.
        // This callback is not executed if the form is cancelled.
        let originalCallback = Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication
        Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication = (returnValue) => {
            originalCallback(returnValue)
            RedirectToContact()
        }
    
        // Because Opportunities isn't created, and CRM only redirects if an opportunity is created upon lead qualification,
        // we have to write custom code to redirect to the contact instead
        RedirectToContact()
    }
    
    // CRM doesn't tell us when the contact is created, since its qualifyLead callback does nothing unless it finds an opportunity to redirect to.
    // This function tries to redirect whenever the contact is created
    function RedirectToContact(retryCount = 0) {
        if (retryCount === 10)
            return Xrm.Utility.alertDialog("Could not redirect you to the contact. Perhaps something went wrong while CRM tried to create it. Please try again or contact the nerds in the IT department.")
    
        setTimeout(() => {
            if ($("iframe[src*=dup_warning]", parent.document).length)
                return // Return if the duplicate detection form is visible. This function is called again when it's closed
    
            let leadId = Xrm.Page.data.entity.getId()
            $.getJSON(Xrm.Page.context.getClientUrl() + `/XRMServices/2011/OrganizationData.svc/LeadSet(guid'${leadId}')?$select=ParentContactId`)
                .then(r => {
                    if (!r.d.ParentContactId.Id)
                        return RedirectToContact(retryCount + 1)
    
                    Xrm.Utility.openEntityForm("contact", r.d.ParentContactId.Id)
                })
                .fail((_, __, err) => Xrm.Utility.alertDialog(`Something went wrong. Please try again or contact the IT-department.\n\nGuru meditation:\n${err}`))
        }, 1000)
    }
    

    TypeScript definitions:

    declare var Mscrm: Mscrm
    
    interface Mscrm {
        LeadCommandActions: LeadCommandActions
    }
    
    interface LeadCommandActions {
        performActionAfterHandleLeadDuplication: { (returnValue: any): void }
    }
    
    declare var Xrm: Xrm
    
    interface Xrm {
        Page: Page
        SaveMode: typeof SaveModeEnum
        Utility: Utility
    }
    
    interface Utility {
        alertDialog(message: string): void
        openEntityForm(name: string, id?: string): Object
    }
    
    interface ExecutionContext {
        getEventArgs(): SaveEventArgs
    }
    
    interface SaveEventArgs {
        getSaveMode(): SaveModeEnum
        isDefaultPrevented(): boolean
    }
    
    interface Page {
        context: Context
        data: Data
    }
    
    interface Context {
        getClientUrl(): string
    }
    
    interface Data {
        entity: Entity
    }
    
    interface Entity {
        getId(): string
    }
    
    declare enum SaveModeEnum {
        qualify
    }
    

    TypeScript-output:

    function OnSave(executionContext) {
        var eventArgs = executionContext && executionContext.getEventArgs();
        if (!eventArgs || eventArgs.isDefaultPrevented() || eventArgs.getSaveMode() !== Xrm.SaveMode.qualify)
            return;
        var originalCallback = Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication;
        Mscrm.LeadCommandActions.performActionAfterHandleLeadDuplication = function (returnValue) {
            originalCallback(returnValue);
            RedirectToContact();
        };
        RedirectToContact();
    }
    function RedirectToContact(retryCount) {
        if (retryCount === void 0) { retryCount = 0; }
        if (retryCount === 10)
            return Xrm.Utility.alertDialog("Could not redirect you to the contact. Perhaps something went wrong while CRM tried to create it. Please try again or contact the nerds in the IT department.");
        setTimeout(function () {
            if ($("iframe[src*=dup_warning]", parent.document).length)
                return;
            var leadId = Xrm.Page.data.entity.getId();
            $.getJSON(Xrm.Page.context.getClientUrl() + ("/XRMServices/2011/OrganizationData.svc/LeadSet(guid'" + leadId + "')?$select=ParentContactId"))
                .then(function (r) {
                if (!r.d.ParentContactId.Id)
                    return RedirectToContact(retryCount + 1);
                Xrm.Utility.openEntityForm("contact", r.d.ParentContactId.Id);
            })
                .fail(function (_, __, err) { return Xrm.Utility.alertDialog("Something went wrong. Please try again or contact the IT-department.\n\nGuru meditation:\n" + err); });
        }, 1000);
    }