MK Partners Archive for May, 2009

MK Partners’ SaaS TEa Provides Time and Expense Reports Solution

MK Partners, Inc. has released its long anticipated SaaS TEa!  Saas TEa is a great tool to allow your employees to easily input all their expense reports and time cards with little risk of human error.  Employees simply enter basic information pertaining to the time card (period, billable category, related client, number of hours, notes) or the expense report (period, billable category, related client, description of expense, dollar amount, and general ledger code) and SaaS TEa does the rest.  And the best part of Saas TEa is that it is all done inside of Salesforce.com!  This allows employees to fill in their information and submit it for review immediately from where ever they are able to access salesforce.com.

SaaS TEa can be easily customized to fit your needs and approval process.  Employees will no longer have to bug your accounting department with questions on where to find reimbursement forms or how to fill them out.  Once the forms are filled out and submitted, the person designated to approve the reports is notified.  Both the person submitting the expense report and the person/people responsible for approving the reports can follow the up to the minute progress of the approval process until it is completed.

SaaS TEa is also designed to work with Salesforce’s powerful reporting tools, enabling users to be able to fully analyze their expenses per employee or employee group.  Other reports include being able to evaluate hours employees spend on specific clients vs the expected profit from the client, determine an employees value based on the hours and expenses they bill, and much more.

SaaS TEa will greatly enhance the ease and functionality of your company’s time card and expense report submissions, as well as provide a great analytical tool to transform these reports into meaningful data!  For more information or to install SaaS TEa today, check out the Salesforce AppExchange or go click here.

Dynamic Picklist Creation and Sorting

Here’s a way to dynamically create a Picklist in Apex, pre-sort the list, and present it in a Visualforce page. In Salesforce it’s not possible to dynamically change Picklist values without getting deep into Force.com API programming. If you wanted to prepare a list of all Contact field names and their labels including custom fields with current information, you would need to generate this dynamically with metadata. To accomplish this we can generate it in Apex and present it in a way that looks like a native Salesforce Picklist.

I’ve included usable code for grabbing Contact metadata so we can present the field Labels in the list and return the Value (Name, AccountId, OwnerId, CustomField1__c, CustomField2__c, etc.) The goal is to present the field labels in alphabetical order with “–None–” listed at the top. When selected this list will return the Id or actual name of the field as opposed to the presented field label. With these results you can use DML to get or set values in Contact.

Visualforce element:

<apex:pageBlockSectionItem >
   <apex:outputLabel value="Contact:" for="contactlist"/>
   <apex:selectList id="contactlist" value="{!contactField}" size="1">
      <apex:selectOptions value="{!contactFieldOptions}"/>
   </apex:selectList>
</apex:pageBlockSectionItem>

Value=”{!contactField}” is the public property defined in the Apex controller class:

public String contactField {get; set;}

//Function to load and sort Contact field metadata for binding to: “{!contactFieldOptions}”
public void loadContactFields()
{
              Map<String, Schema.SObjectField> m = Schema.SObjectType.Contact.fields.getMap();
              List<Schema.SObjectField> sof = m.values();
              contactFieldOptions = new List<selectOption>();
              Map<String, String> tmp = new Map<String, String>();
              List<String> tmp2 = new List<String>();

              for(Schema.SObjectField s : sof)
              {
                            tmp.put(s.getDescribe().getLabel(), s.getDescribe().getName()); // Reversed for sorting
                            tmp2.add(s.getDescribe().getLabel());
              }

              tmp2.sort(); // Sort by field label, not field name
              selectOption so = new selectOption('NONE', '--None--'); // Native SF look and feel
              contactFieldOptions.add(so); // Build the Select List

              for(String s : tmp2)
              {
                            so = new selectOption(tmp.get(s), s);
                            contactFieldOptions.add(so);
              }
}

Finally, you can use the result(s) for dynamic Apex operations such as SOQL:
s = Database.query(contactField + ‘, Namespace__CustomField1__c from Contact limit 1000′);

Vegas baby, Vegas!

I love going to the mail box (yes, I still use snailmail) and finding a flyer from a casino in Las Vegas offering me a free room.  I quickly make my flight reservation and soon I’m sitting at a blackjack table.  Almost without fail, an hour or two later I wind up walking away from a blackjack table poor and cursing the day I received the free promo.  How did they know I was going to end up spending more money on restaurants and shows and losing money on gambling than they could ever charge on that room?!  Because salesforce.com told them so.

Many casinos are using salesforce.com to track all of their clients’ activities while in Vegas.  The casinos are then easily able to use this information to see if a client spends/loses significantly more money when in town than the cost of a hotel room.  Most of the time it’s pretty obvious that getting people to the casinos, even by offering rooms for free, is well worth it.  Salesforce’s ability to relate clients to all their opportunities is a great way to evaluate not only how much of a return casinos get for a client’s visit in the past, but also how likely of a return they can expect if they continue to entice clients to return to the casino.

Casinos also use the Salesforce platform to track clients’ air reservations, spending at restaurants in the casino, and tickets to many of the Vegas Strip shows.  Salesforce’s cloud computing gives casinos the flexibility to allow agents to make reservations for clients on their system and see client ratings, history, and air travel plans.  Salesforce’s secure platform has resolved any concerns casinos may have associated with having their information stored at a third party.  Harrah’s, which has a family of casinos around the world, sees the power of cloud computing as a real asset for casinos that they can leverage to better understand their clients.

So next time you receive a free room offer you may want to think twice, because the casinos have salesforce.com on their side.  Speaking of which, I think I hear the mailman outside…and it’s time to plan my next trip to Vegas.

Email ESP with Gmail

Wouldn’t it be great to know what emails are in your inbox before Gmail has even loaded. The folks over at Gmail Labs have made it possible with a new feature called Inbox Preview.    Inbox Preview adds a sneak peak of your inbox to the Loading screen that you first see when launching Gmail.  You can turn on this feature by clicking on Settings and then Labs in Gmail.  This works in both personal and Google Apps versions.

We figure this can save you at least 2 seconds each time you open Gmail, possibly more depending on the size of your inbox.  That’s at least 30 minutes a year, assuming you open/refresh Gmail a few times a day.  Enjoy!

Inbox Preview

Inbox Preview

Salesforce as a Platform for Change

Regardless of your line of business, empowering your customers and constituents is a goal that all organizations share. Our constituents drive our organizations to grow, evolve, and deliver better services and products.

In our busy world, it can be difficult to reach out to constituents. Between personal lives, work schedules, travel schedules, and time differences, it can be a daunting task to really communicate with our constituency groups. With salesforce.com, organizations no longer have to worry about figuring out how to have an effective dialogue with constituents.

Utilizing salesforce.com’s Ideas functionality, organizations big and small can leverage technology to drive change both internally and externally.

One of the best examples of how salesforce.com can be leveraged to drive change is to review how President Obama used Ideas functionality during his transition period to offer Americans a forum to share their thoughts, concerns, and ideas with the incoming administration.

Check out Paul Greenberg’s article on how the Obama transition team utilized salesforce.com to generate communication between Americans and our nation’s leadership. Greenberg discusses that this type of technology can be useful to all organizations regardless of sector.

Have you had any success using salesforce.com Ideas? Has your organization struggled with finding an effective way to involve constituents in your growth?

Deriving Website from Email Addresses

Ever look at a lead record and want to know more about it.  Your first instinct might be to visit the Lead’s website.  Don’t you hate it when the website field is blank but the email isn’t.  You have to copy the domain from the email address and then paste it into your browser.  That’s a minimum of 4 clicks and keystrokes.  What a waste of time!

Wouldn’t it be great, if you could automatically populate the website field based on email address? This solution is so simple that you’re going to hit yourself for not implementing it sooner.

1. Create a new Workflow Rule on Leads with the following filters:
Email contains @
Website equals [leaving the value blank]

2. Add a Workflow Field Update that updates the Website field with this formula:
“www.”& RIGHT(Email, LEN(Email)- FIND(“@”, Email ) )

3. Activate and enjoy!

You can also use this same formula to create a Custom Link for this purpose. You can also optionally filter out common domains like gmail if you want to.

Pick a number 1-10, randomly, with Apex

In the past when we’ve had to come up with a random number, we’ve leveraged the randomness of when the user performed an operation. We would look at the minute or second that a function ran to come up with a number that would be somewhat random.

There’s actually a much easier way to do this and it’s built-in to Apex. The below code will pick a random number out of a range that you set. It’s extremely simple, enjoy!

public Integer randomNumber(Integer range)
{
Double x = math.random() * range;
return x.intValue();
}

Dynamically inserting the results from Dynamic SOQL

This is the 3rd post in a series discussing some complex code we’ve written for recent projects. Our first post detailed performing a query using Dynamic SOQL. Our second post detailed using the Describe method to compile a string of fields used in the Dynamic SOQL query. This third post demonstrates how to reinsert the results of the query.

The actual use case involved a custom clone/archive function that copied a new lead to a custom object. When copying from one object to another you have to ensure that all custom fields have the same API Name and then manually set any standard fields. To simplify the code, this example will copy a contact to a new contact.

//Function to clone existing Contact with dynamic APEX
public static void copyContact()
{
//Create a map from the results of a Describe of the Contact Object
Map<String, Schema.SObjectField> cFieldMap = Schema.SObjectType.Contact.fields.getMap();

//Generate a comma delimited String of Contact Fields
String conFields = '';
for ( String f : cFieldMap.keySet() )
{
	conFields += f;
	conFields += ',';
}
conFields = conFields.subString(0,conFields.Length() -1);

//Define a Where clause
String whereClause = 'WHERE Lastname != null ';

//Define an Order By clause to sort your query
String orderBy = ' Order By MailingState ';

//Define your entire Query as a string
String qryString = 'SELECT ' + conFields + ' FROM Contact ' + whereClause + orderBy + ' limit 1';

//Query salesforce with your Query string
List<Contact> queryResults = Database.query(qryString);

//Create a list of new contacts to insert
List<Contact> contactInserts = new List<Contact>();

for (Contact c : queryResults)
{
	Contact newC = new Contact();
	for ( String f : cFieldMap.keySet() )
	{
		Schema.SObjectField contactField = cFieldMap.get(f);
		Schema.DescribeFieldResult dfr = cFieldMap.get(f).getDescribe();
		if ( c.get(contactField) != null && dfr.isUpdateable() )
		{
			newC.put( cFieldMap.get(f), c.get(contactField) );
		}
	}
	contactInserts.add(newC);
}

insert ContactInserts;
}

Apex Describe with Dynamic SOQl

This is the 2nd post in a series discussing some complex code we’ve written for recent projects. Our first post detailed performing a query using Dynamic SOQL. In that post, you had to hard-code the Contact fields that you wanted to query. This isn’t always ideal. Sometimes you want to query all fields on the object and you don’t want to edit your code each time you add a new field.

You can accomplish this task by using the field describe result’s getMap() method. Which returns a map of field names and field describe details. Don’t worry about the field describe details portion of the Map, for now we just want the Map’s keySet, which contains every field on the Contact object.

The below code adds to our post from last week, using the above concept to compile a string of field names to use in our SOQL query.

public class website_WebServices
{
//Function to perform Dynamic SOQL query on Contacts
public static <Contact> getContacts(String whereClause)
{
//Create a map from the results of a Describe of the Contact Object
Map<String, Schema.SObjectField> cFieldMap = Schema.SObjectType.Contact.fields.getMap();

//Generate a comma delimited String of Contact Fields
String conFields = '';
for ( String f : cFieldMap.keySet() )
{
conFields += f;
conFields += ',';
}
conFields = conFields.subString(0,conFields.Length() -1);

//Define an Order By clause to sort your query
String orderBy = ' Order By MailingState ';

//Define your entire Query as a string
String qryString = 'SELECT ' + conFields + ' FROM Contact ' + whereClause + orderBy + ' limit 10';

//Query salesforce with your Query string
List<Contact> queryResults = Database.query(qryString);

return queryResults;
}

//Sample Where Clause
public static String whereClause = 'WHERE Lastname != null ';

//Sample function to get a list of Contacts by passing the Where Clause to the getContacts function
public static list<contact> contacts = getContacts(whereClause);

}