Data Controls Implementation Guide

Data Controls Implementation Guide

Implementation

Implementation

The following prerequisites are assumed for integration of Duplicate Prevention control into the Salesforce applications:
  • Customer data is stored in the Salesforce application as a standard Salesforce object, Contact.
  • Data from the Salesforce application is loaded into the Hub Server. Source System for the data from Salesforce is named SFDC and the internal field Contact.id, which are used to uniquely identify Salesforce objects mapped as PKEY_SRC_OBJECT column in the Hub. The Hub Server base object that stores customer records is named C_CUSTOMER.
  • The C_CUSTOMER base object is configured to use a fuzzy match/merge strategy. It has a match column named Customer_Name, with type Person_Name, which is a Fuzzy Match Key. This match column is used to find matches on full names of people. For more information, see the section on configuring the match process in the
    Multidomain MDM Configuration Guide
    .
  • The IDD application is configured and deployed. SubjectArea that uses C_CUSTOMER base object for its PrimaryObject is named Customer.
  • An instance of Duplicate Prevention IDC control is created as part of the IDD application, with the name
    dp.
Firstly, control should be configured to use the Source System, SFDC, that was used to load data from Salesforce as the target system. Also, assume that for importing records from the Hub Server, we need values of PrimaryObject columns, FIRST_NAME and LAST_NAME only. During the import into Salesforce these columns are mapped to the corresponding columns of Contact object. The following configuration file, pmc-config.xml, must be uploaded to configure the control:
<?xml version="1.0" encoding="UTF-8"?> <pmcConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="
siperian-bdd-config-6.xsd
" systemName="SFDC"> <mdmEntity name="Customer" sourceEntity=" Customer"> <columnMapping columnUid=" C_CUSTOMER |FIRST_NAME" sourceColumn="FirstName"/> <columnMapping columnUid=" C_CUSTOMER |LAST_NAME" sourceColumn="LastName"/> </mdmEntity> </pmcConfig>
On the Salesforce side, the standard process of new contact creation should be overridden to use Duplicate Prevention capabilities. In this example a two-step wizard is used instead of the default, new Contact page:
  1. User enters new Contact data and clicks
    Save.
    The user is redirected to the second page, which contains Duplicate Prevention control displaying the potential matches found.
  2. User can use this page to handle events generated by the control and if the control notifies the page that no matched records are found, then the new Contact is automatically saved. Otherwise, the user can open or import the found matched records, proceed with saving the new Contact or cancel the save operation:
This approach to integrate Duplicate Prevention control into the Salesforce application is used only to demonstrate some aspect of work with the control. You can use other strategies for integration with Salesforce.
To implement this wizard, you must define two pages and a custom controller that keeps data entered by the user, coordinates navigation between pages, and handles Open and Import actions.
The following is a sample Apex code for the controller (which extends the standard Contact controller):
public class duplicatePreventionWizardController { /* field keeps id of the selected matched record, (field is set by JavaScript code handling ON_OPEN event) */ private String matchedRecordId; /* next two fields keep values of FIRST_NAME and LAST_NAME fields of the imported matched record (fields are set by JavaScript code handling ON_OPEN event) */ private String importedFirstName; private String importedLastName; // reference to the standard Contact controller private ApexPages.StandardController stdController; public duplicatePreventionWizardController(ApexPages.StandardController stdController) { this.stdController = stdController; } // returns reference to the first wizard's page, used to control navigation public PageReference returnToEdit() { return Page.NewContact_Step1; } // returns reference to the second wizard's page, used to control navigation public PageReference searchForDuplicates() { return Page.NewContact_Step2; } // generate search criteria string needed to build URL invoking Duplicate Prevention control public String getMatchParametersString() { // get data entered by user Contact contact = (Contact)stdController.getRecord(); String firstname = contact.FirstName != null ? contact.FirstName : ''; String lastname = contact.LastName != null ? contact.LastName : ''; // construct full name used for matching as FirstName + LastName String fullName = firstname + ' ' + lastname; // values of IDC parameters should be double encoded fullName = doubleEncode(fullName); // search criteria should be passed in format 'mc.<match column name>:<match column value>' (Customer_Name is name of match column configured in Hub) String matchParameters = 'mc.Customer_Name:' + fullName; return matchParameters; } // function implements double encoding for IDC parameters private String doubleEncode(String str) { return EncodingUtil.urlEncode(EncodingUtil.urlEncode(str, 'UTF-8'), 'UTF-8'); } // open selected matched record public PageReference openMatch() { try { // try to find Contact using id passed in ON_OPEN event and redirect to the Contact view page Contact matchedContact = [select id from Contact where id = :matchedRecordId]; PageReference matchViewPage = new ApexPages.StandardController(matchedContact).view(); matchViewPage.setRedirect(true); return matchViewPage; } catch (Exception e) { ApexPages.Message message = new ApexPages.Message(ApexPages.Severity.FATAL, 'Failed to load object with id ' + matchedRecordId); ApexPages.addMessage(message); return null; } } // import selected matched record public PageReference importObject() { try { // try to create Contact using data passed in ON_IMPORT event and redirect to the Contact view page Contact importedContact = new Contact(FirstName = importedFirstName, LastName = importedLastName); insert importedContact; PageReference importedViewPage = new ApexPages.StandardController(importedContact).view(); importedViewPage.setRedirect(true); return importedViewPage; } catch (Exception e) { ApexPages.Message message = new ApexPages.Message(ApexPages.Severity.FATAL, 'Failed to save object'); ApexPages.addMessage(message); return null; } } // getters and setters required to access controller's attributes using <apex:param> tag public String getMatchedRecordId() { return matchedRecordId; } public void setMatchedRecordId(String matchedRecordId) { this.matchedRecordId = matchedRecordId; } public void setImportedFirstName(String value) { importedFirstName = value; } public String getImportedFirstName() { return importedFirstName; } public void setImportedLastName(String value) { importedLastName = value; } public String getImportedLastName() { return importedLastName; } }
The following code defines the first wizard page and contains input fields required to enter new Contact record. To simplify the example, only fields required to perform search for duplicates (contact's first name and last name) are used.
<!-- page NewContact_Step1 (uses custom duplicatePreventionWizardController) --> <apex:page standardController="Contact" extensions="duplicatePreventionWizardController"> <apex:form > <apex:pageBlock > <apex:pageBlockButtons > <!-- Save button invokes 'searchForDuplicates' action, it redirects user to the second page --> <apex:commandButton action="{!searchForDuplicates}" value="Save"/> <!-- Cancel button invokes standard 'cancel' action --> <apex:commandButton action="{!cancel}" value="Cancel" immediate="true"/> </apex:pageBlockButtons> <!-- fields to input Contact FirstName ane LastName --> <apex:pageBlockSection title="Contact Information"> <apex:inputField value="{!contact.firstName}"/> <apex:inputField value="{!contact.lastName}"/> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>
The following code defines the second wizard page. It displays the Contact data entered by the user in read-only view and the found potential duplicates. This page has two additional buttons:
Skip
Skips this page and proceeds with save.
Cancel
Returns to the first page.
The URL invoking duplicate prevention control is generated dynamically using Contact data entered by user. The JavaScript code handling Duplicate Prevention events extracts data passed in events and invokes corresponding actions defined in the controller:
<!-- page NewContact_Step2 (uses custom duplicatePreventionWizardController) --> <apex:page standardController="Contact" extensions="duplicatePreventionWizardController"> <!-- include postmessage JavaScript plugin --> <script type="text/javascript" src="http://postmessage.freebaseapps.com/postmessage.js"></script> <apex:form id="mainForm"> <!-- panel displaying error messages --> <apex:outputPanel id="messages"> <apex:messages style="font-weight:bold; color:red;"/> </apex:outputPanel> <script> // function handles events generated by Duplicate Prevention control function handleEvent(data) { switch(data['action']) { case 'ON_LOAD': if (data['duplicatesFound'] == 'false') { // if duplicates are not found proceed with save continueSave(); } break; case 'ON_OPEN': // try to find and open Contact using id passed in event openMatchedRecord(data['id']); break; case 'ON_IMPORT': // convert JSON string passed in event into JavaScript object var record = eval('(' + data['record'] + ')'); // try to save and open Contact using data from Hub passed in event importObject(record.Customer.FirstName, record.Customer.LastName); break; } } // register function handleEvent as handler for Duplicate Prevention events function bindHandler() { pm.bind("idd_pmc_event", function(data) { handleEvent(data); }); } bindHandler(); </script> <!-- JavaScript functions invoking methods defined in controller, used by code handling events --> <apex:actionFunction name="openMatchedRecord" action="{!openMatch}" reRender="messages"> <apex:param name="matchedRecordId" assignTo="{!matchedRecordId}" value=""/> </apex:actionFunction> <apex:actionFunction name="importObject" action="{!importObject}" reRender="messages"> <apex:param name="firstName" assignTo="{!importedFirstName}" value=""/> <apex:param name="lastName" assignTo="{!importedLastName}" value=""/> </apex:actionFunction> <apex:actionFunction name="continueSave" action="{!save}" reRender="mainForm"/> <apex:pageBlock id="mainPanel"> <apex:pageBlockButtons > <!-- Skip button invokes standard save action --> <apex:commandButton action="{!save}" value="Skip" immediate="true"/> <!-- Cancel button redirects user to the first page --> <apex:commandButton action="{!returnToEdit}" value="Cancel" immediate="true"/> </apex:pageBlockButtons> <apex:pageBlockSection title="Contact Information"> <apex:outputField value="{!contact.firstName}"/> <apex:outputField value="{!contact.lastName}"/> </apex:pageBlockSection> <!-- IFRAME embedding Duplicate Prevention control, URL is constructed using string generated by controller --> <iframe src="http://host:port/bdd/bdc/dp/sa:Customer,{!matchParametersString}/proactive_match/component.jsf" style="width:100%;height:500px"></iframe> </apex:pageBlock> </apex:form> </apex:page>
To enable JavaScript messaging in Internet Explorer 7, Duplicate Prevention control requires the
parentUrl
parameter. You must pass the value of this parameter to the Duplicate Prevention control. To achieve this code of NewContact_Step2 page, embedding component using HTML tag
<iframe>
can be changed for Internet Explorer 7 to dynamically detect current URL and insert it as a parameter into the URL invoking the control as shown:
<!-- IFRAME embedding Duplicate Prevention control, URL is constructed using string generated by controller and dynamically detected URL of the current page--> <script> var parentUrl = encodeURIComponent(encodeURIComponent(document.location.href)); var url = 'http://host:port/bdd/bdc/dp/sa:Customer,' + '{!matchParametersString}' + ',parentUrl:' + parentUrl + '/proactive_match/component.jsf'; document.writeln('<iframe src="' + url + '" style="width:100%;height:500px"></iframe>'); </scrip>
To configure Salesforce to use the implemented wizard for new Contact creation:
  1. Navigate to
    Setup
    Customize
    Contacts
    Button
    Links
    .
  2. Click the
    Edit
    link for the New action.
  3. Select the first wizard's page,
    NewContact_Step1
    to override the value of the URL.

0 COMMENTS

We’d like to hear from you!