Configure Account/Opportunity Integration

This page shows how to integrate Pricefx Unity to the MS Dynamics Account/Opportunity page using IFrame.

Please carefully review and modify the script below, ensuring that you follow all the comments provided within the script.

  1. Go to MS Dynamics > Opportunity > Form to start customizing (or MS DynamicsAccount > Form).

    image2019-12-12_15-13-52.png


    (In some MSD versions, the Form button is not there. Alternatively, go to Settings > Customizations > Customize the System > Entities > Account / Opportunity.)

  2. Add a Tab, a Section and an iframe to the desired place (using the Insert tab of the ribbon).

    image2019-12-12_15-15-45.png
  3. Configure the iframe’s properties as below:

    1. General tab:

      1. Name (iframe name should be unique): IFRAME_<iframe name>

      2. URL: https://<customer cluster domain name>/pricefx/<partition name>/saml/consume?RelayState=<Relay State Name>

      3. Restrict cross-frame scripting, where supported: unchecked

        image2019-12-12_15-18-24.png
      4. Click OK to create it, then double click it to continue editing its properties.

    2. Switch to the Event tab:

      1. In Form Library, add a library with the script in the attached file.

        image2019-12-12_15-32-42.png
      2. Choose New to create a JS library.

        image2019-12-12_15-53-38.png
      3. Enter Name, Display Name, Description and select Script (JScript) Type for this web resource, then click the Text Editor button to add this script.

        image2019-12-12_15-56-33.png
      4. Add the following scripts as JavaScript web resource and save it.

        JavaScript
        var PFXRegisterListener = function () { //TODO: change to unique name
          if (window.XMLHttpRequest) {
            //for browsers other than ie
            window.parent.parent.addEventListener("message", PFXInputsLookup, false); //TODO: change PFXInputsLookup
          } else {
            window.parent.parent.attachEvent("onmessage", PFXInputsLookup); //TODO: change PFXInputsLookup
          }
        
          window.parent.document.getElementById("IFRAME_<iframe name>").style.height =
            "1000px"; // TODO: edit height if needed
        };
        
        var PFXInputsLookup = function (event) { //TODO: change to unique name and update all occurrences
          if (event.origin != "https://<customer cluster domain name>") { //TODO: add customer cluster domain name
            return;
          }
          var jsonData = JSON.parse(event.data);
        
          var action = jsonData.action;
          var data = jsonData.data;
        
          var entity = parent.window.Xrm.Page.data.entity;
        
          switch (action) {
            case "getEntityInfo":
              console.log("..DYNAMICS.eventHandler getEntityInfo", action);
              var response = {};
              response.entityName = entity.getEntityName();
              response.id = entity.getId();
              response.accountnumber = entity.attributes
                .get("accountnumber")
                .getValue();
              event.source.postMessage(JSON.stringify(response), event.origin);
              break;
            case "setDashboardInputs":
              console.log("..DYNAMICS.eventHandler setDashboardInputs", action);
              var id = entity.getId();
              data.fields.forEach(function (fieldName) {
                var attribute = entity.attributes.get(fieldName);
                if (attribute) {
                  data[fieldName] = attribute.getValue();
                }
              });
        
              var response = {};
              response.id = id;
              response.data = data;
              response.entityName = entity.getEntityName();
              event.source.postMessage(JSON.stringify(response), event.origin);
              break;
            case "getPayload":
              console.debug("DYNAMICS - message received from PRICE FX", jsonData);
              var payload = {};
              entity.attributes.forEach(function (attribute) {
                var attributeName = attribute.getName();
                payload[attributeName] = attribute.getValue();
              });
              response.action = action;
              payload.id = id;
              payload.entityName = entity.getEntityName();
              response.data = payload;
              event.source.postMessage(JSON.stringify(response), event.origin);
              break;
            case "getAccount": {
              console.log("..DYNAMICS.eventHandler getAccount", action);
              var account = parent.window.Xrm.Page.data.entity.attributes
                .get("parentaccountid")
                .getValue()[0];
              if (account) {
                Xrm.WebApi.retrieveRecord(
                  "account",
                  account.id,
                  "?$select=name,accountnumber"
                ).then((result) => {
                  console.info("Successful get account", result);
                  var accountNumber = result.accountnumber;
                  if (!data.lineItemFields) {
                    var entity = {
                      id: id,
                      data: data,
                      action: action,
                      accountnumber: accountNumber,
                      entityName: parent.window.Xrm.Page.data.entity.getEntityName(),
                      lineItems: [],
                      customerName: result ? result.name : null,
                    };
                    event.source.postMessage(JSON.stringify(entity), event.origin);
                  }
                });
              }
              break;
            }
            case "findOpportunities":
              console.log("..DYNAMICS.eventHandler findOpportunities", action);
              var xmlhttp = new XMLHttpRequest();
              xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                  var opportunities = [];
                  var response = JSON.parse(xmlhttp.responseText);
                  for (var i = 0; i < response.value.length; ++i) {
                    var opportunity = response.value[i];
                    opportunities.push({
                      Id: "{" + opportunity.opportunityid + "}",
                      Name: opportunity.name,
                    });
                  }
                  event.source.postMessage(
                    JSON.stringify({ id: "1", data: opportunities }),
                    event.origin
                  );
                }
              };
              xmlhttp.open(
                "GET",
                "/api/data/V8.0/opportunities/?$select=name&$top=10&$filter=contains(name,'" +
                  data.searchText +
                  "')",
                true
              );
              xmlhttp.send();
              break;
            case "createNewQuote":
              console.log("..DYNAMICS.eventHandler createNewQuote", action);
              var id = entity.getId();
        
              data.fields.forEach(function (item) {
                const foundItem = entity.attributes.get(item.id);
                if (foundItem) {
                  item.value = foundItem.getValue();
                }
              });
        
              var account = parent.window.Xrm.Page.data.entity.attributes
                .get("parentaccountid")
                .getValue()[0];
              if (account) {
                Xrm.WebApi.retrieveRecord(
                  "account",
                  account.id,
                  "?$select=name,accountnumber"
                ).then((result) => {
                  console.info("Successful get account", result);
                  var accountNumber = result.accountnumber;
                  if (!data.lineItemFields) {
                    var entity = {
                      id: id,
                      data: data,
                      action: action,
                      accountnumber: accountNumber,
                      entityName: parent.window.Xrm.Page.data.entity.getEntityName(),
                      lineItems: [],
                      customerName: result ? result.name : null,
                    };
                    event.source.postMessage(JSON.stringify(entity), event.origin);
                  }
                });
              }
        
              response.id = id;
              response.data = data;
              response.entityName = entity.getEntityName();
              response.accountnumber = entity.attributes
                .get("accountnumber")
                .getValue();
              response.customerName = entity.attributes.get("name").getValue();
              response.action = action;
              event.source.postMessage(JSON.stringify(response), event.origin);
              break;
          }
        
          return;
        };
        
        

        Please note the condition that checks the event origin and updates the right URL. Here is a sample for the demo cluster:

        if (event.origin != 'https://demo.pricefx.eu') {
        return;
        }

        Depending on the MS Dynamics entity, you have to complete the TODO in the script to pass the needed value to Pricefx. For details you can refer to https://docs.microsoft.com/en-us/previous-versions/dynamicscrm-2016/developers-guide/gg328474(v=crm.8).

      5. Save and publish this web resource, then get back to the iframe properties / Events tab.

      6. In the Event Handler section, select OnReadyStateComplete UI Event and add an item which is:

        1. Library: Library name that you have just added in Step iii

        2. Function: PFXRegisterListener

        3. Select the Enabled option.

          image2019-12-12_16-22-45.png
  4. Finally, save and publish your change. You will see Pricefx integrated to the Opportunity detail page.