Microsoft Dynamics

Custom JavaScript Functions

Prerequisites

This document is specifically to outline custom code functions and assumes general knowledge of the PandaDoc integration for Microsoft Dynamics. If you are not yet familiar, refer to the articles below first.

Microsoft Dynamics CRM Integration with PandaDoc
Microsoft Dynamics CRM Integration with PandaDoc - Install and Setup

Capabilities

Standard integration logic can be redefined via custom functions for three cases:

Get Recipients List

Create a function with the name according to the template #customentityname#_getRecipients. As shown in the screenshot above, this function receives entity as a parameter which contains custom entity object and returns jQuery.Promise which is resolved as an array of recipients. (jQuery.Promise is used to allow additional ajax calls within custom functions to retrieve additional data).

Get Products List

Create a function with the name according to the template #customentityname#_getProducts.jQuery.Promise returned by this function is resolved as an array of products.

[hidden]: <> (Get a Whole Object Passed to PandaDoc)
[hidden]: <> (Create a function named by the template #customentityname#_getData.jQuery.Promise returned by this functions is resolved as a fully formed data object pulled with data (tokens, recipients, products etc).)

Custom Function Examples

function new_customentity_getRecipients(entity) {
    var deferred = jQuery.Deferred();

    var recipient = {};
    recipient.email = '[email protected]';
    recipient.first_name = 'John';
    recipient.last_name = 'Appleseed';
    recipient.phone = '0123456789';
    recipient.company = 'PandaDoc';
    recipient.roleName = "Signer";

    deferred.resolve([recipient]);
    return deferred.promise();
}
function opportunity_getProducts(entity) {
  var deferred = $.Deferred();

  $.ajax({
    type: "GET",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    url: encodeURI(Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/" + "OpportunitySet(guid'" + entity.OpportunityId + "')/product_opportunities?$expand=opportunity_products"),
    beforeSend: function (xmlHttpRequest) {
      xmlHttpRequest.setRequestHeader("Accept", "application/json");
    }
  }).then(function (result) {
    var items = result.d.results.map(function (op) {
      return {
        sku: op.OpportunityProductId,
        name: "Banana Product",
        price: parseFloat(op.PricePerUnit.Value),
        qty: parseFloat(op.Quantity),
        description: (op.opportunity_products && op.opportunity_products.Description ? op.opportunity_products.Description : op.Description) || "",
        currency: op.TransactionCurrencyId.Name || "",
        custom_fields: {
          // here would be your custom fields for pricing table, for example
          custom_field_1: "This is bananas!!!"
        }
      };
    });
    deferred.resolve(items);
  });

  return deferred.promise();
}
function opportunity_getProducts(entity) {
    var deferred = $.Deferred();

    $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        url: encodeURI(Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/" + "OpportunitySet(guid'" + entity.OpportunityId + "')/product_opportunities?$expand=opportunity_products&$orderby=SequenceNumber"),
        beforeSend: function (xmlHttpRequest) {
            xmlHttpRequest.setRequestHeader("Accept", "application/json");
        }
    }).then(function (result) {
        var items = [];
        var anotherProducts = [];
        //custom section
        items.push({
            isSection: true,
            name: "Products that start with 'test'"
        });
        result.d.results.map(function (op) {
            var product = {
                sku: op.OpportunityProductId,
                name: op.ProductDescription || (op.ProductId ? op.ProductId.Name : ""),
                price: parseFloat(op.PricePerUnit.Value),
                qty: parseFloat(op.Quantity),
                description: (op.opportunity_products && op.opportunity_products.Description) || op.Description || "",
                currency: op.TransactionCurrencyId.Name || "",
                custom_fields: {}
            };
            if (product.name.startsWith('test')) {
                items.push(product);
            } else {
                anotherProducts.push(product);
            }
        });
        if (anotherProducts.length > 0) {
            items.push({
                isSection: true,
                name: "Another products"
            });
            items = items.concat(anotherProducts);
        }
        deferred.resolve(items);
    });

    return deferred.promise();
}

Implementation

In order to redefine standard behavior and utilize custom logics to form data sent to PandaDoc.

❗️

Please note

We do not support the "null" value in custom_fields, please avoid using it.

1. Open custom entity form.

- Settings -> Customizations -> Entities -> Custom entity -> Forms -> Main form
###2. Open Form properties

1029

3. Click Add in Form Libraries section

1026

4. Click New and enter Name (example - customentity.to.pandadoc.js).

- Select Type ‘Script (JScript)’ and click Save

822

5. Click Text Editor button to open a window where you can create custom Javascript functions.

1026

6. Add the Script to Dynamics

After the function is created:
- Close the editor.
- Click save.
- Select your file in the libraries list.
- Click add.

1026

7. Using the up button, move your file above the pandadoc_/Components/EntityForms/form.bundle.js

1032

8. Publish all Customizations

- Click Ok -> Save -> Publish
- Reload the page so that changes take effect.