This is the documentation for Clover Club 12.0.
Documentation for the upcoming version Rampur 13.0 can be found here.

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 Dynamics > Account > Form).


    (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).

  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

      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.

      2. Choose New to create a JS library.

      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.

      4. Add the following scripts as JavaScript web resource and save it.

        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:

        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.

  4. Finally, save and publish your change. You will see Pricefx integrated to the Opportunity detail page.