Sunday 15 December 2013

Salesforce: Validation Rules

Validation rules verify the data entered into fields is of the correct data type and meets the standards you set before a record can be saved.

You can use boolean formulas that evaluates the field data and results in true/false statements.


You also have to specify an error message if the user breaks a validation rule on save due to an invalid value.


Salesforce processes rules in the following order:

  1. Validation rules
  2. Assignment rules
  3. Auto-response rules
  4. Workflow rules (with workflow actions)
  5. Escalation rules

Also:
  • When one validation rule fails, Salesforce continues to check any additional validation rules on that field or any other field on the page and displays all appropriate error messages at once.
  • If validation rules exist for activities and you create an activity during lead conversion, the lead converts but a task isn’t created.
  • Validation rules are only enforced during lead conversion if validation and triggers for lead conversion are enabled in your organization.
  • Campaign hierarchies ignore validation rules.
  • Salesforce runs validation rules before creating records submitted via Web-to-Lead and Web-to-Case, and only creates records that have valid values.
  • Validation rules continue to run on individual records if the owner is changed. If the Mass Transfer tool is used to change the ownership of multiple records, however, validation rules won’t run on those records.

How to create a validation rule:

  1. Navigate to the relevant object, field, campaign member, or case milestone.
  2. In the Validation Rules related list, click New.
  3. Enter the properties of your validation rule.
  4. To check your formula for errors, click Check Syntax.
  5. Click Save to finish or Save & New to create additional validation rules.

Example Validations:


Validates that the account Billing Zip/Postal Code is in the correct format if Billing Country is Canada.
AND(OR(BillingCountry = "CAN", BillingCountry = "CA", BillingCountry = "Canada"),
NOT(REGEX(BillingPostalCode, "((?i)[ABCEGHJKLMNPRSTVXY]\\d[A-Z]?\\s?\\d[A-Z]\\d)?"))
)

Validates that the account Billing Zip/Postal Code is valid by looking up the first five characters of the value in a custom object called Zip_Code__c that contains a record for every valid zip code in the US. If the zip code is not found in the Zip_Code__c object, or the Billing State does not match the corresponding State_Code__c in the Zip_Code__c object, an error is displayed.

VLOOKUP(
$ObjectType.Zip_Code__c.Fields.City__c ,
$ObjectType.Zip_Code__c.Fields.Name ,
LEFT(BillingPostalCode,5)) <> BillingCity

Validates that the account Billing Zip/Postal Code is in 99999 or 99999-9999 format if Billing Country is USA or US.AND(
OR(BillingCountry = "USA", BillingCountry = "US"),
NOT(REGEX(BillingPostalCode, "\\d{5}(-\\d{4})?"))
)

Validates that the Account Number is numeric if not blank. AND(
   ISBLANK(AccountNumber),
   NOT(ISNUMBER(AccountNumber))
)

Validates that the Account Number is exactly seven digits (if it is not blank). The number seven is simply illustrative.AND(
   ISBLANK(AccountNumber),
   LEN(AccountNumber) <> 7
)

Validates that a custom field called Hours Worked is not a negative number
Hours_Worked__c < 0Validates that the contact Mailing StreetMailing City, and Mailing Country are provided.OR(   ISBLANK( MailingStreet ),
   ISBLANK( MailingCity ),
   ISBLANK( MailingCountry )
)

Validates that the value of a custom date field is a weekday (not Saturday or Sunday).
CASE(MOD( My_Date__c - DATE(1900, 1, 7), 7),
0, 0,
6, 0,
1) = 0






Friday 6 December 2013

Visualforce: Overriding an Existing Page with a Visualforce Page

Make each section for an account display in a tab, such as contacts, opportunities

Create a Visualforce page:
goto setup - develop - pages - new
type tabbedaccount for the label and name for the page and then copy this code:

<apex:page standardController="Account" showHeader="true" 
      tabStyle="account" >
   <style>
      .activeTab {background-color: #236FBD; color:white; 
         background-image:none}
      .inactiveTab { background-color: lightgrey; color:black; 
         background-image:none}
   </style>
   <apex:tabPanel switchType="client" selectedTab="tabdetails" 
                  id="AccountTabPanel" tabClass='activeTab' 
                  inactiveTabClass='inactiveTab'>   
      <apex:tab label="Details" name="AccDetails" id="tabdetails">
         <apex:detail relatedList="false" title="true"/>
      </apex:tab>
      <apex:tab label="Contacts" name="Contacts" id="tabContact">
         <apex:relatedList subject="{!account}" list="contacts" />
      </apex:tab>
      <apex:tab label="Opportunities" name="Opportunities" 
                id="tabOpp">
         <apex:relatedList subject="{!account}" 
                           list="opportunities" />
      </apex:tab>
      <apex:tab label="Open Activities" name="OpenActivities" 
                id="tabOpenAct">
         <apex:relatedList subject="{!account}" 
                           list="OpenActivities" />
      </apex:tab>
      <apex:tab label="Notes and Attachments" 
                name="NotesAndAttachments" id="tabNoteAtt">
         <apex:relatedList subject="{!account}" 
                           list="CombinedAttachments" />
      </apex:tab>
   </apex:tabPanel>
</apex:page>

Now that you've created a page to display an account with tabs, you can use this page to override the detail view for all accounts.
From Setup, click Customize | Accounts | Buttons, Links, and Actions.
Click Edit next to View.
For Override With select Visualforce Page.
From the Visualforce Page drop-down list, select tabbedAccount.
Click Save.
Click the Account tab, and select any account. The detail for the account is now displayed with tabs.

Monday 2 December 2013

Apex - Setting up Eclipse

There are 4 steps to setting up Eclipse to work with Salesforce:

  • INSTALL JAVA
  • DOWNLOAD ECLIPSE
  • INSTALL FORCE.COM IDE PLUGIN FOR ECLIPSE
  • CONFIGURING ECLIPSE WITH YOUR ORG

INSTALL JAVA
Eclipse was originally written for the Java platform. It still requires a Java Runtime Environment (JRE) or a Java Development Kit (JDK)

DOWNLOAD ECLIPSE:
Eclipse is modular software. The link is: Download Eclipse Standard 4.3.1 here

The file is about 199 MB in size, so it will take a while to download. You will end up with a .ZIP file. Unpack the file. Move the unpacked folder to  c:\eclipse. You can now start Eclipse by double-clicking it.


FORCE.COM IDE ECLIPSE PLUGIN INSTALL:
Now log into your salesforce org and goto setup - develop - tools and download force.com ide plugin for eclipse:



Copy the entire contents of the plugin folder from the force.com IDE plugin download into the plugins folder of the eclipse folder at c:\eclipse\plugins

Now follow these steps


  1. Launch Eclipse and click Help > Install New Software

    Install New Software

  2. Click Add....
  3. In the Add Repository dialog, set the Name to "Force.com IDE" and the Location to "http://media.developerforce.com/force-ide/eclipse42" and click OK. (Use the same URL for Eclipse 4.3.)

    Add Site

  4. Eclipse downloads the list of available plugins and displays them in the Available Software dialog.
  5. Check the box next to the Force.com IDE plugin and click Next.

    Select Force.com IDE plugin

  6. In the Install Details dialog, click Next.
  7. In the Review Licenses dialog, accept the terms and click Finish.
  8. Eclipse downloads and installs the Force.com IDE and any required dependencies. When installation is complete, you will be prompted to restart. Click Yes.
  9. When Eclipse restarts, select Window > Open Perspective > Other, select Force.com and click OK.

note you may prefer this:
  1. Launch Eclipse and select Help | Install New Software.
  2. Click Add.
  3. In the Add Repository dialog, set the name to Force.com IDE and the location tohttps://developer.salesforce.com/media/force-ide/eclipse45. For Spring ’16 (Force.com IDE v36.0) and earlier Force.com IDE versions, use http://media.developerforce.com/force-ide/eclipse42.
  4. Click OK.
  5. To install an older version of the plug-in (for example, if you don’t have Java 8), deselect Show only the latest versions of available software.
    Eclipse downloads the list of available plug-ins and displays them in the Available Software dialog.
  6. Select the Force.com IDE plug-in, and then click Next.
  7. In the Install Details dialog, click Next.
  8. In the Review Licenses dialog, accept the terms and click Finish.
  9. If you choose to install support for Lightning components, Eclipse displays a warning dialog about installing software that contains unsigned content. We are bundling third-party plug-ins to support Lightning components. Salesforce doesn’t own these third-party plug-ins; hence, we don’t sign them. Click OK to proceed.
  10. Eclipse downloads and installs the Force.com IDE and the required dependencies. When the installation is complete, you are prompted to restart. Click Yes.
  11. When Eclipse restarts, select Window | Open Perspective | Other. Select Force.com and then click OK.
    You are now ready to develop and customize Force.com applications in Eclipse!

CONFIGURING ECLIPSE WITH YOUR ORG

To create a new project in eclipse, click file - new.  
you will be prompted to login to your org and create a project name:

You can now choose to download all or some of the metadata already in your org



TIP - before  logging into your org  from Eclipse,  enter the IP of your PC into Salesforce Setup - Security Controls - Network Access.  You can find your IP by using ipconfig/all in the command prompt.

Friday 29 November 2013

Salesforce Demo: Cross object formulas - adding lead owner email to lead record

This video shows how to add the lead owners email to the lead record using a cross object formula.



One benefit of doing this is so that you can report on lead owners email (unique field) and potentially saves you using a vlookup command from report export from the user object and lead object.

Some objects support different object types for the Owner field, such as a User, Queue, or Calendar. On objects that support this behavior, when creating a cross-object formula using Owner, you must be explicit about the owner type you’re referencing.

For example, if you need owner email and you don’t use queues, your formula would be Owner:User.Email. If you do use queues, your formula could be:

IF( ISBLANK( Owner:User.Id ), Owner:Queue.QueueEmail, Owner:User.Email )

Here’s how you would select Owner object fields on a Lead in the Advanced formula tab:
Formula Span to Owner

Thursday 28 November 2013

SOQL Demo: Use Workbench to create a SOQL

Workbench can be used to build SOQL commands.Use this link to sign in to Workbench. You will need to be signed into your Salesforce environment.

Salesforce Object Query Language is very similar to SQL but not as powerful.  It's an easy language to learn.

SOQL uses the SELECT statement combined with filtering statements to return sets of data, which may optionally be ordered:

SELECT one or more fields
FROM an object
WHERE filter statements and, optionally, results are ordered

For example, the following SOQL query returns the value of the Id and Name field for all Account records if the value of Name is Sandy:

SELECT Id, Name
FROM Account
WHERE Name = 'Sandy'

This process is very much like producing a salesforce report but is more time effective way to get the data you need.

Soql Guide

Watch this video:




Upwards traversal - from child to parent - via lookup or master-detail relationship
SELECT Id, Account.Name, Account.Industry, Account.Website
    FROM Contact

    WHERE Account.NumberOfEmployees >= 200

referencing account fields (parent) from contact (child) using dot notation

SELECT Account.Owner.Profile.CreatedBy.Name FROM Contact

You can traverse multiple levels upwards

SELECT Id, customlookupfield__r.customfield__c from contact

Here we’re traversing a custom lookup field customlookupfield__c on the contact object. Notice how the “__c” changes to a “__r” when traversing that field
Downwards traversal - from parent to child - via related list
SELECT Id, Name, Industry, AnnualRevenue,
    ( SELECT Name, Email, BirthDate FROM Contacts )

    FROM Account
nested soql is like another field, nested object uses the plural, (child relationship name found in object settings)

Simple query
SELECT Name FROM Account WHERE Name like 'A%'
SELECT Id FROM Contact WHERE Name LIKE 'A%' AND MailingCity='California'

Query filter on DateTime
SELECT Name FROM Account WHERE CreatedDate > 2011-04-26T10:00:00-08:00
SELECT Name FROM Account WHERE CreatedDate > 2011-04-26T10:00:00Z

Query with Date Function
SELECT Amount FROM Opportunity WHERE CALENDAR_YEAR(CreatedDate) = 2011

Query filter on null 
SELECT AccountId FROM Event WHERE ActivityDate != null

Query Multi-Select Picklists
SELECT Id, MSP1__c from CustObj__c WHERE MSP1__c includes ('AAA;BBB','CCC')
this will return record with MSP__1 example: 'AAA;BBB;DDD' ; 'CCC;EEE'

Semi-Join Query
SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Opportunity WHERE StageName = 'Closed Lost')

Reference Field Semi-Join Query
SELECT Id FROM Task WHERE WhoId IN ( SELECT Id FROM Contact WHERE MailingCity = 'Twin Falls' )

Anti-Join Query
SELECT Id FROM Account WHERE Id NOT IN ( SELECT AccountId FROM Opportunity WHERE IsClosed = false )

Reference Field Anti-Join Query
SELECT Id FROM Opportunity WHERE AccountId NOT IN ( SELECT AccountId FROM Contact WHERE LeadSource = 'Web' )

Multiple Semi-Joins Query
SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Contact WHERE LastName LIKE 'apple%' )
AND Id IN ( SELECT AccountId FROM Opportunity WHERE isClosed = false )

Relationship Query: parent to child
SELECT Id, (SELECT Id from OpportunityLineItems) FROM Opportunity

Relationship Query: child to parent 
SELECT Id, Name, Account.Name FROM Contact

Relationship Query: Polymorphic 
A polymorphic relationship field in object being queried that can reference multiple object types. For example, the What relationship field of an Event could be an Account, or a Campaign, or an Opportunity.
SELECT Id FROM Event WHERE What.TYPE IN ('Account', 'Opportunity')

With OFFSET
Use OFFSET to specify the starting row offset into the result set returned by your query.
SELECT Id, Name FROM Opportunity ORDER BY Name OFFSET 5

With GROUP BY
From API version 18.0 and later, you can use GROUP BY with aggregate functions, such as COUNT(), SUM() or MAX()
SELECT Stagename, COUNT(Id) FROM Opportunity GROUP BY Stagename

SELECT LeadSource, COUNT(Name) FROM Lead GROUP BY LeadSource
SELECT Stagename, SUM(amount) FROM Opportunity GROUP BY Stagename
SELECT CALENDAR_YEAR(CloseDate), COUNT(Id) FROM Opportunity GROUP BY CALENDAR_YEAR(CloseDate) ORDER BY CALENDAR_YEAR(CloseDate)

With GROUP BY ROLLUP
Same with GROUP BY, with additional ROLLUP, it add subtotal for aggregated data in the last row
SELECT Stagename, COUNT(Id) FROM Opportunity GROUP BY ROLLUP(Stagename)


With GROUP BY ROLLUP with 2 fields
SELECT Status, LeadSource, COUNTId) FROM Lead GROUP BY ROLLUP(Status, LeadSource)

HAVING in GROUP BY
You can use a HAVING clause with a GROUP BY clause to filter the results returned by aggregate functions, same with WHERE with normal query
SELECT LeadSource, COUNT(Id) FROM Lead GROUP BY LeadSource HAVING COUNT(Id) > 2

Querying Currency Fields in Multi-currency Organizations
SELECT Id, Name FROM Opportunity WHERE Amount > JPY5000
without currency code it will use organization's default currency

Salesforce Demo: Creating a sales process, record types and a pagelayout

Sometimes it's just much easier to watch the video:


Tuesday 26 November 2013

Salesforce Demo: Creating a simple workflow rule

Sometimes it's just much easier to watch the video:


Note: Rather than use "criteria is met" as in this video, you could use "formula evaluates to true" and "Amount  >= 5000 &&   (IsClosed  = false)"

Salesforce: Mass add member to Chatter group

Salesforce.com give 5,000 chatter free licenses, it is good for an organisation to use Chatter for collaboration as it is free. But, adding hundreds or thousands of users to Chatter groups will take you weeks and make you wish for a better life.


Luckily.......
You can use Data Loader to mass add SF users to Chatter group.


1. Open Data Loader
2. Click on Insert
3. Username  &  Password (SecurityToken if applicable) 
4. Click  Next
5. Click Checkbox for Show All Salesforce Objects, Find Chatter Group Member(CollaborationGroupMember)












6. Click Browse then  *select file* (CSV Type) That contains the additions - you will need a column for Chatter Group Id and User ID
7. Click  Next Then Okay 
8. Click Create or Edit a Map then Auto-Match Fields to Columns (Where possible)
9. Manually map any additional fields left out of the mapping - Map "CollaborationGroupId" to Chatter Group Id and MemberId to User Id
10. Click Okay Then Next 
11. Click Browse To *select directory* to store the success & error files
12. Click Okay Then Click Finish 

Saturday 23 November 2013

Salesforce - Buttons to Mass delete records / Get ids / Show google maps / Create a new record - URL hack /Clone a record - URL Hack/ insert a complete record - onclick javascript

Mass Delete


This example creates a button that can be added to activity related lists and list views, and allows users to delete selected records at the same time.
1 Define a button for events with these atributes:
Display Type─List Button
behavioue - execute javascript
content source - onclick javascript
add this code:
{!REQUIRESCRIPT("/soap/ajax/9.0/connection.js")}
var records = {!GETRECORDIDS( $ObjectType.Event )};
var taskRecords = {!GETRECORDIDS( $ObjectType.Task)};
records = records.concat(taskRecords);

if (records[0] == null) {
alert("Please select at least one record.") }
else {
var errors = [];
var result = sforce.connection.deleteIds(records);
if (result && result.length){
var numFailed = 0;
var numSucceeded = 0;
for (var i = 0; i < result.length; i++){
var res = result[i];
if (res && res.success == 'true'){
numSucceeded++;
} else {
var es = res.getArray("errors");
if (es.length > 0) {
errors.push(es[0].message);
}
numFailed++;
}
}
if (numFailed > 0){
alert("Failed: " + numFailed + "\nSucceeded: " + numSucceeded + " \n Due to: " + errors.join("\n"));
} else {
alert("Number of records deleted: " + numSucceeded);
}
}
window.location.reload();
}

2 add button to activity list views
3 add button to  to any page layout that contains an activity related list. The button deletes any selected task or event in the list.

Getting Record IDs

This example creates a button that opens a popup window listing record IDs for user selected records. This is useful when testing to ensure you have the correct record IDs before processing them further.

1 Define a button for events with these atributes:
Display Type─List Button
behavioue - execute javascript
content source - onclick javascript
add this code:
idArray = {!GETRECORDIDS($ObjectType.Contact)};
alert("The Ids you have selected are: "+idArray);

2 add button to  to the appropriate related list on a page layout or list view layout.

Get Google Map

This example creates a button that opens a new window showing a google map.  This is useful for anyone wanting to make a site visit.

1 define a new button at customise - accounts - actions links buttons with these attributes:
Display Type─Detail Page Button
behavioue - display in new window
content source - URL
add this code:

http://maps.google.com/maps?q={!Account_BillingStreet}%20{!Account_BillingCity}%20{!Account_BillingState}%20{!Account_BillingPostalCode}
2 add button too account page layout

Create a new record - url hack

1 Define a button for events with these atributes:
Display Type─List Button
behavioue - display in exiting window without sidebar or header
content source - URL

2 Define the URL as below:

the code to insert will essentially open the edit pagelayout for the object you want to create a new record with some values prepopulated from another related record.  This is usefull to save the user some time linking records correctly.

the url doesn't need the “https://na15.salesforce.com/” so the url starts after the / with “/a0U/e” - a0U is an object code and e represents edit so to find this simply push edit on on a relevant record and check the url in the browser whilst on the edit page (https://na15.salesforce.com/a0U/e?) you dont need the "?"

/a0U/e

so this is now good enough to place on a related list via the page layout editor but you will want to add values

to add values you will need to add the ? its used as a seperator

now goto setup of the object you are creating a record for and click on the field you want to preopulate and grab the field id from the url, you will then write in your field id and objectname.fieldname like this

/a0U/e?00Ni000000EpsgY={!Opportunity.Description}

for a lookup field you add CF to the front of the id

CF00Ni000000EpsgO

as this is a lookup we add the relationship parameter  add “_lkid” to the end of the id

/a0U/e?CF00Ni000000EpsgO={!Opportunity.Name}&CF00Ni000000EpsgO_lkid={!Opportunity.Id}

notice & is used to seperate fields

/a0U/e?00Ni000000EpsgY={!Opportunity.Description}&CF00Ni000000EpsgO={!Opportunity.Name}&CF00Ni000000EpsgO_lkid={!Opportunity.Id}

finally add a return url incase user cancels midway or on the save of the record

&retURL={!Opportunity.Id}  this will take yu back to the original record where you have placed your button
/a0U/e?00Ni000000EpsgY={!Opportunity.Description}&CF00Ni000000EpsgO={!Opportunity.Name}&CF00Ni000000EpsgO_lkid={!Opportunity.Id}&retURL={!Opportunity.Id} 

Clone a record - URL Hack

Here's an example for cloning a user record:
/{!User.Id}/e?clone=1&retURL=%2F{!User.Id}&name_firstName=&name_lastName=&Alias=&Email=&Username=&CommunityNickname=

you can see that by leaving some fields blank (eg. name_firstName=)  that you will not copy that fields value into the cloned record

insert a complete record onclick javascript


a - button to create a record
b - button to create a related child record
c - button to create parent and related child record

button to create a record
1 Define a button for events with these atributes:
Display Type─List Button
behavioue - Execute JavaScript

content source - onclick

2 define the javascript code:

you must include the libraries so add the following on the first line

{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}

you'll need to create an object variable to hold our data. for example “acct”, as an Account record.

var acct = new sforce.SObject("Account");

now just populate the fields on the object like so

acct.name = 'New Account';
acct.phone = '515-123-4567';

Now that I have all my fields defined, I’m ready to save the new record.

var result = sforce.connection.create([acct]);

last is 

if(result[0].getBoolean("success")){
window.location = "/" + result[0].id + "/e";
}else{
alert('Could not create record '+result);

}


button to create a related child record if you are creating a child record you will have to identify the lookupfield to the parent

var parent = new sforce.SObject(“parent__c”);
parent.id = “{!lookuptoparentfromchildfield__c.Id}”;

create the child

var child = new sforce.SObject(“child__c”);

set field values for child

child.lookuptoparentfromchildfield__c = parent.id;
child.childfield2__c = “Test”;

save record

var result = sforce.connection.create([child]);

verify result

// verify the results
if(result[0].getBoolean(“success”)){
window.location = “/” + result[0].id + “/e”;
}else{
alert(‘Could not create record ‘+result);
}

button to create parent and related child record
you could combine both into one button like this:

{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
var parent = new sforce.SObject("parent__c");
var start = new Date;

parent.name = 'parentname';
parent.account_name__c = "{!Account.Id}";
parent.contact_name__c = "{!Contact.Id}";
parent.Due_Date__c = new Date(start.setDate(start.getDate() + 1));
parent.stage__c = "New";
parent.currencyisocode = 'GBP';

var resultparent = sforce.connection.create([parent]);

if(resultparent[0].getBoolean("success")){
 var newparentId = resultparent[0].id;
 var child = new sforce.SObject("child__c"); 

child.easy_opportunity__c = newparentId; 
 child.Sale_Price__c = "0.00"; 
 child.Status__c = "New"; 
 child.Name = "childname"; 
 child.CurrencyIsoCode = 'GBP'; 

 var resultchild = sforce.connection.create([child]); 

 if(resultchild[0].getBoolean("success")){ 
  window.location = "/" + newparentId; 
 }else{ 
  alert('Could not create record '+resultchild); 
 }
}else{
 alert('Could not create record '+resultparent);

}