Nuxeo Add-Ons

Nuxeo for Salesforce

The Nuxeo for Salesforce addon allows Salesforce (SFDC) users to attach documents to their Salesforce Objects (such as Opportunities, Contacts, Accounts...) through the Salesforce UI within a Nuxeo server.

See GitHub Readme for the Dev project description.

Functional Overview Video

Watch this video for a functional overview.

Installation and Configuration

Installation

This addon requires no specific installation steps. It can be installed like any other package with nuxeoctl command line or from the Update Center.

Salesforce Configuration

In your Salesforce account, you can setup the Nuxeo for Salesforce plugin through the Salesforce Marketplace (in progress).

You can also set it up directly from your Salesforce dashboard. Note that these instructions assume you are using "Salesforce Classic", not the "Lightning Experience".

Although the Canvas app can be displayed within this new environment, it will still be unstable ("Lightning Experience" is in a beta state on Salesforce side). You can activate the Lightning Experience or disable it via Setup Home > Lightning Experience. Scroll to the bottom to disable it.

  1. Go in your Salesforce dashboard.
  2. Go on Setup (top right).
  3. Go to Build > Create > Apps.
  4. Click the New button under Connected Apps named Nuxeo (it MUST be named "Nuxeo"):
    1. Enable OAuth settings and set the callback URL: https://NUXEO_URL/nuxeo/picker/callback/callback.html .
    2. Add all available Scopes.
    3. Enable Force.com Canvas and set the App URL https://NUXEO_URL/nuxeo/picker
    4. Select OAuth Webflow for Access Method.
    5. Configure Canvas App locations by adding Layouts and Mobile Cards.
  5. Save the "Nuxeo" Connected App.
  6. Go to Build > Customize and choose any SFDC Object, e.g. "Opportunities".
  7. Click on Page Layouts to edit the SFDC Object page layout.
  8. Add the Nuxeo Canvas App anywhere in the page.
    • Hint: choose "Canvas Apps" in the list of available objects.
    • Tip: if you add a new "Section" you need to save the layout before you can drop the Nuxeo Canvas App.
  9. Save the layout. Now when an Opportunity is opened the Nuxeo widget will be enabled. You have now access to the consumer key of the nuxeo app, this will be needed in the Nuxeo Platform Configuration part.

Nuxeo Platform Configuration

  1. To authorize the framing of your Nuxeo server inside Salesforce, edit your nuxeo.conf file by adding the following line (no value expected):
nuxeo.frame.options =
  1. Set up the HTTPS configuration. Salesforce requires the Nuxeo server to be accessed through HTTPS. Follow this documentation to configure your reverse proxy for production purpose. For a dev or test environment, you can configure your Nuxeo server in HTTPS directly with the following configuration parameters example:

    nuxeo.server.https.port=8443
    nuxeo.server.https.keystoreFile=/Users/vpasquier/nuxeo.keystore
    nuxeo.server.https.keystorePass=******
    

    Don't forget to include the https template in the nuxeo.template parameter of your nuxeo.conf file.

    You can setup the keystore by following the Oracle documentation or directly run keytool -genkey -v -keystore nuxeo.keystore -alias tomcat -keyalg RSA -keysize 2048 -validity 10000.

  2. Add the following configuration parameter (in Admin > Cloud Services > Service Providers > OAuth2 Service Providers > Add):

    Service Name=salesforce
    CliendID=YOUR_SALESFORCE_CONSUMER_KEY
    User Authorization URL=https://NUXEO_URL/nuxeo/picker/callback/callback.html
    
  3. Set up your browser to access Nuxeo for Salesforce from within Salesforce.

    1. Authorize Popups from Salesforce (to allow OAuth execution).
    2. Go to [https://NUXEO_URL/nuxeo] and allow Chrome to access in HTTPS your Nuxeo server.

Synchronization - Salesforce vs Nuxeo

The default behaviour of Nuxeo Salesforce plugin is to bind the current Salesforce Object to a Workspace document type and the way the metadata are synchronized. This document type Workspace has a new facet salesforce to store the SF object id.

Each time a SF user is displaying a SF object in his SF console, Nuxeo is going to create/retrieve the related workspace, listing all its children.

Default Behavior

The Automation operation script javascript.FetchSFObject can be overridden in order to bind the current Salesforce object to a specific document in Nuxeo.

javascript.FetchSFObject

<scriptedOperation id="javascript.FetchSFObject">
  <inputType>void</inputType>
  <outputType>void</outputType>
  <category>javascript</category>
  <script>
    function run(input, params) {
      var sfobject = {};
      sfobject.id = params.sfobjectId;
      sfobject.name = params.sfobjectName;
      var docs = Repository.Query(null, {
        'query': "SELECT * FROM Document WHERE ecm:isTrashed = 0 AND sf:objectid = '" + sfobject.id + "' AND ecm:isVersion = 0 AND ecm:mixinType != 'HiddenInNavigation'",
      });
      if (docs.length>0) {
        return Repository.GetDocument(null, {
          'value': docs[0].id
        });
      } else {
        var workspaces = Repository.GetDocument(null, {
            "value" : "/default-domain/workspaces"
        });
        var newSFobject = Document.Create(workspaces, {
              "type" : "Workspace",
              "name" : sfobject.name,
              "properties" : {
                  "dc:title" : sfobject.name,
                   "sf:objectid" : sfobject.id
              }
        });
        return newSFobject;
    }}]]>
  </script>
</scriptedOperation>

In the operation, the parameter param of the function provides three attributes: sfobjectid, sfobjectname and sfobjecttype.

Override Example

Here is an example of overriding the SF object binding: When I enter my SF object, like account or an opportunity, the operation below is executed.

  1. Nuxeo checks if this object is already bound with a Nuxeo document through sfobject.id.
  2. It returns the Nuxeo document if exists.
  3. If the Nuxeo object doesn't exist, it creates it in the appropriate location:
    • If the SF object is an account, place it under the document /default-domain/workspaces/Custom or under his parent account.
    • If the SF object is an opportunity, place it under his parent account.
  4. The metadata are synchronized from Salesforce to Nuxeo (checking if metadata have been changed).

This behavior is implemented by this operation.

New Behavior

function run(input, params) {
      var sfobject = JSON.parse(params.sfObject);
      // We are checking if the document is existing. If not we're going to check the rules to create it accordingly.
      var docs = Repository.Query(null, {
        'query': "SELECT * FROM Document WHERE ecm:isTrashed = 0 AND sf:objectId = '" + sfobject.Id + "' AND ecm:isVersion = 0 AND ecm:mixinType != 'HiddenInNavigation'",
      });
      if (docs.length>0) {
        return nuxeoDocument(docs[0],sfobject);
      } else {
        var newSFobject = {};
          // We are checking if an account has a parent account or not and create it beneath the appropriate document.
          if(sfobject.attributes.type === "Account") {
            if(sfobject.ParentId ===  null){
              var proposals = Repository.GetDocument(null, {
                  "value" : "/default-domain/workspaces/Custom"
              });
              newSFobject = Document.Create(proposals, {
                    "type" : "ParentAccount",
                    "name" : sfobject.Name,
                    "properties" : {
                        "dc:title" : sfobject.Name,
                         "sf:objectId" : sfobject.Id
                    }
              });
            }else{
              var parents = Repository.Query(null, {
                'query': "SELECT * FROM Document WHERE ecm:isTrashed = 0 AND sf:objectId = '" + sfobject.ParentId + "' AND ecm:isVersion = 0 AND ecm:mixinType != 'HiddenInNavigation'",
              });
              newSFobject = Document.Create(parents[0], {
                    "type" : "AccountName",
                    "name" : sfobject.Name,
                    "properties" : {
                        "dc:title" : sfobject.Name,
                         "sf:objectId" : sfobject.Id,
                         "sf:Parent_Account" : parents[0]["dc:title"];
                    }
              });     
            }
          } else {
            if(sfobject.Contract_ID === null) {
              var accounts = Repository.Query(null, {
                'query': "SELECT * FROM Document WHERE ecm:isTrashed = 0 AND sf:objectId = '" + sfobject.AccountId + "' AND ecm:isVersion = 0 AND ecm:mixinType !=  'HiddenInNavigation'",
              });
              var account = accounts[0];
              var properties = getProperties(newSFobject, sfobject);
              properties["dc:title"]=sfobject.Name;
              properties["sf:objectId"]=sfobject.Id;
              newSFobject = Document.Create(account, {
                    "type" : "OpportunityName",
                    "name" : sfobject.Name,
                    "properties" : properties
              });
            }
          }
        return newSFobject;
       }
}
function nuxeoDocument(doc, sfobject){
  if(sfobject.attributes.type === "Account") {
    var account = Repository.GetDocument(null, {'value': doc.id});
    return account;
  }else{
    var dirtyProperties = getProperties(doc, sfobject);
    var opportunity = Document.Update(
    doc, {
      'properties': dirtyProperties
    });
    return opportunity;
  }
}
function getProperties(doc, sfobject){
  var dirtyProperties = {};
  if(sfobject.Contract_ID!==doc["sf:Contract_ID"]){
    dirtyProperties["sf:Contract_ID"]=sfobject.Contract_ID;
  }
  if(sfobject.Task_Order_Number!==doc["sf:Task_Order_Number"]){
    dirtyProperties["sf:Task_Order_Number"]=sfobject.Task_Order_Number;
  }
  if(sfobject.Contract_Ceiling_Value!==doc["sf:Contract_Ceiling_Value"]){
    dirtyProperties["sf:Contract_Ceiling_Value"]=sfobject.Contract_Ceiling_Value;
  }
  if(sfobject.StageName!==doc["sf:Stage"]){
    dirtyProperties["sf:Stage"]=sfobject.StageName;
  }
  return dirtyProperties;
}

Customization with Nuxeo Studio

Those two operations can be overridden inside a Nuxeo Studio project easily by creating two operations for instance: SFGetChildren and FetchSFObject.

Documents Listing

Default Behavior

The Automation operation script javascript.SFGetChildren provides a way for the developer to customize the listing of the document content bound to the Salesforce object.

javascript.SFGetChildren

<scriptedOperation id="javascript.SFGetChildren">
  <inputType>document</inputType>
  <outputType>documents</outputType>
  <category>javascript</category>
  <script>
    function run(input, params) {
        return Document.GetChildren(input, {});
    }}]]>
  </script>
</scriptedOperation>

Override Example

For instance, the listing execution could be executed in an unrestricted session to list "unauthorized" documents only for title viewing (Salesforce or Nuxeo rights are not affected).

javascript.SFGetChildren

function run(input, params) {
  Auth.LoginAs(null, {});
  var children =  Document.GetChildren(input, {});
  Auth.Logout(null, {});
  return children;
}

Customization with Nuxeo Studio

Those two operations can be overridden inside a Nuxeo Studio project easily by creating two operations for instance: SFGetChildren and FetchSFObject.


25 days ago Manon Lumeau NXDOC-1079 Remove videos from Doc
a month ago manonlumeau Remove updated review date
2 years ago Solen Guitter 40 | ix format and lin
2 years ago Anne Jubert 39
2 years ago Anne Jubert 38
2 years ago Anne Jubert 37
2 years ago Anne Jubert 36
2 years ago Anne Jubert 35
2 years ago Anne Jubert 34
2 years ago Anne Jubert 33
2 years ago Anne Jubert 32
2 years ago Vladimir Pasquier 31
2 years ago Joshua Fletcher 30
2 years ago Solen Guitter 29
2 years ago Joshua Fletcher 28 | Improve SFDC docs.
3 years ago Solen Guitter 27
3 years ago Solen Guitter 26
3 years ago Vladimir Pasquier 25
3 years ago Vladimir Pasquier 24
3 years ago Vladimir Pasquier 23
3 years ago Vladimir Pasquier 22
3 years ago Vladimir Pasquier 21
3 years ago Vladimir Pasquier 20
3 years ago Vladimir Pasquier 19
3 years ago Vladimir Pasquier 17
3 years ago Vladimir Pasquier 18
3 years ago Vladimir Pasquier 16
3 years ago Vladimir Pasquier 14
3 years ago Vladimir Pasquier 15
3 years ago Vladimir Pasquier 13
3 years ago Solen Guitter 12 | NXDOC-658: Marketplace packages are now called Nuxeo Packages, format
3 years ago Vladimir Pasquier 11
3 years ago Vladimir Pasquier 10
3 years ago Vladimir Pasquier 9
3 years ago Vladimir Pasquier 8
3 years ago Vladimir Pasquier 7
3 years ago Vladimir Pasquier 5
3 years ago Vladimir Pasquier 6
3 years ago Vladimir Pasquier 4
3 years ago Vladimir Pasquier 2
3 years ago Vladimir Pasquier 3
3 years ago Vladimir Pasquier 1
History: Created by Vladimir Pasquier

We'd love to hear your thoughts!

All fields required