Showing posts with label Salesforce. Show all posts
Showing posts with label Salesforce. Show all posts

Friday, September 4, 2015

Where's My Flow/Process in the Change Set?

If you've tried deploying flows or processes in a change set, especially in a large change set, you may have experienced some disorientation trying to find that in the Change Set detail page. For quick reference, the table below shows you what you should be looking for when examining an open change set vs. a closed change set.

Component Type Ordered By (in Open Change Set) Ordered By (in Closed Change Set)
Flows Unique Name Flow Name
Processes API Name Process Name

Monday, August 31, 2015

What's the Real Risk with Enabling Divisions?

In Salesforce, divisions are a means to improve query and search performance by partitioning data into logical buckets called "divisions". However, like with the Person Accounts feature, many admins may hesitate and think twice about enabling divisions due to this warning: "Enabling divisions is irreversible. After implementing divisions, you cannot revert back to a state that does not have division fields."

"Irreversible", huh? Well... what's the real risk with enabling divisions? I think there is no significant risk.

According to Salesforce Help (Summer '15), enabling divisions may affect (or not) nine key areas. But it seems like the effects can be easily negated or suppressed.

Area Reversal Strategy
SearchRevoke the "Affected by Divisions" permission.
List viewsRevoke the "Affected by Divisions" permission.
ChatterNot supported (i.e., affected).
ReportsRevoke the "Affected by Divisions" permission.
Viewing records and related listsNot affected.
Creating new recordsSet to the global division.
Editing recordsSet to the global division.
Custom objectsSet to the global division.
RelationshipsSet to the global division.

In short, if you want to give divisions a try, talk to a few people about enabling the feature. If the foremost argument against enabling divisions is simply that it's irreversible, go ahead and just enable it anyway (in a full sandbox first). If it doesn't work for you, you can always revoke the Affected by Divisions permission from all users.

Friday, August 14, 2015

6 Salesforce Target Attributes Every PowerCenter Session Should Set

When using Informatica PowerCenter to perform ETL jobs that process large data volumes (think millions of records), there are at least six attributes that should be set for each session. And even when loading smaller data volumes, these attributes may still be worth setting to improve performance.

1. Max batch size = 10000


The assumption here is that the session will use the Bulk API, which is the fastest way to load data in Salesforce. Period. As of Summer '15, the maximum batch size for a Bulk API job is still 10,000 records. Let's take advantage of this.

2. Set fields to NULL = checked


With data loads, by default it's best to assume that a blank field means that there is no data from the source system to feed this field. In this case, whatever is currently in the field would be considered invalid, to be overwritten with a blank value during the feed.

3. Use SFDC Bulk API = checked


Self-explanatory.

4. Monitor Bulk Job Until All Batches Processed = checked


When chaining tasks inside a worklet or workflow, monitoring the bulk job until all batches are processed helps to ensure that a dependent task will start only after the predecessor task truly completes. Otherwise, not only would you increase the risk of encountering locking errors, you run the risk of the next task running in the context of stale data.

5. Enable field truncation attribute = unchecked


This is equivalent to the Allow field truncation setting in Salesforce Data Loader. Unfortunately still, as of Summer '15, using the Bulk API prevents us from using this automatic truncation option. So you should be aware that truncating values must be done by other means during the transformation, not the load!

6.Enable hard deletes for BULK API = checked


Why not? This significantly improves the performance of mass delete operations, by skipping the Recycle Bin and erasing the record immediately.

Tuesday, June 30, 2015

Salesforce Change Set Accelerators

Okay, so this post isn't really about web accelerators in the purest sense of the definition. But if you're frustrated with the experience of navigating and managing change sets in the UI, here are a few quick bookmarklets you can add to your browser to ease the pain.

To "install" a bookmarklet, simply drag the bookmarklet on to your browser's bookmarks bar. Or, in Internet Explorer, right-click the bookmarklet and click Add to favorites...

Last Tested Date: June 30, 2015 (Summer '15)

Change Set: Next


CS > Next

Ever notice that sometimes when you click Next to scroll through the pages of 25 components in a change set, the size of the table shifts and displaces the Next link? This simple bookmarklet clicks the Next link for you, without you having to move your mouse cursor.

Change Set: Previous


CS > Previous

Same as the Change Set: Next bookmarklet, but for the Previous link.

Add to Change Set: more (10,000 records per list page)


AtCS > more (10,000)

When adding components to a change set, especially for something like Custom Fields, you may have noticed two frustrating problems. First, clicking through multiple pages to find the record you want is a pain. Second, multiplying the pain is the fact that what you select on one page is lost when you switch to a different page. This bookmarklet sort of solves the problem by upping the size of the list to 10,000 records, which usually is enough to allow you to select and add all components of the same type at once.

Other tips


If you're planning to create a large change set as you build out your solution over multiple days or weeks, bookmarking the change set's detail page in your sandbox org should be a quick win.

Sunday, May 31, 2015

Why Roll-Up Summary Requires Master-Detail

There's an idea that is 7 years old on the Success Community titled, "Eliminate Need for Master-Detail Relationship for Roll-ups", and users have voted the idea up to over 25,000 points.


I won't lie. I am most likely one of the 2,500 users who voted in favor of the idea, who thought I can't believe a no-brainer like this is still an idea and not a GA feature!

But today, while watching Who Sees What: Record Access Via Sharing Rules I suddenly realized that the reason for the delay could actually be ridiculously simple: Implementing this feature would violate the security design of the Salesforce1 Platform. How? By exposing information that would otherwise be hidden when OWD is set to "Private".

Scenario: VIP bank accounts


Let's say you're a system administrator for a fictitious financial institution called SaaS Bank. At SaaS Bank, there are everyday customers, and then there are VIP customers. VIP customers at SaaS Bank are high-profile individuals of great importance or great wealth, and a few notable VIPs include Barack Obama, Warren Buffett and Marc Benioff.

Understandably, VIPs get the white glove treatment. Their relationships are discretely managed by handful of bankers in the Private Bank department within SaaS Bank. These bankers are known as Private Bankers, and their number one priority is protecting their client's sensitive data, namely the clients' bank accounts and balances.

Data on customers' bank accounts are stored in a custom object labeled Bank Account, and all bank accounts serviced by SaaS Bank are tracked in this object.

The security requirement: Everyone at SaaS Bank should be able to see that a VIP is indeed a customer, but only Private Bankers (and their trusted colleagues) should be able to see the bank accounts held by a VIP.

The simple solution would be to make the Bank Account custom object private using OWD. And to relate Bank Account records back to a customer (i.e., a standard Account record), the object has a Lookup(Account) field, not a Master-Detail(Account) field.

The tricky requirement: All users want to see aggregate balance data for their customers.

So, if you could create a Roll-Up Summary field on the Account object that sums all balances for a customer, you would violate the private sharing model for the Bank Account object. A Roll-Up Summary field holds a value that is calculated based on all pertinent records.

In a private sharing model, how would... how could the Roll-Up Summary field hold a value that simultaneously shows 0 to a regular banker, the total balance to a Private Banker and something in between to other bankers with whom a Private Banker has manually shared records? The answer is it can't.

Objects with Master-Detail fields inherit the record access controls on parent objects. In this case you can present aggregate information on parent records via Roll-Up Summary fields, because if you have access to the parent record you also have access to all child records. But when you use a Lookup field instead because you need different record access for child records, well...

Okay, I get it, and I still need a workaround


I think there are legitimate reasons why an organization would want aggregate data to be automatically calculated and displayed through a Lookup relationship. There are two ways to work around this:
  • Ignore the built-in security constraint and leverage Apex running in system context to perform the roll-up. You can even use an off-the-shelf solution the free Declarative Lookup Rollup Summaries app or the paid Rollup Helper app.
  • Use a custom visual element (e.g., Visualforce page) to display a contextual roll-up, taking into account the current user's access to child records. This would leverage the with sharing keyword to accurately display different values to different users.

In the end, it would be nice of either of the above options were made into native features. And I'm guessing that the first option, the convenient and intentional deviation from an established security model, is what the 2,500 supporters of that 7-year-old idea want.

Who Sees What: Record Access Via Roles (Corrected)

I'm admittedly a bit disappointed in the Who Sees What: Record Access Via Roles video. When I first read about the Who Sees What series, I thought it was awesome that salesforce.com decided to produce visual aids on the topic of security. As an alternative to the Security Implementation Guide, which boasts over 100 pages of official documentation on Salesforce security, I expected the videos to demystify the flexible and nuanced security controls available to system administrators.

However, after watching the Record Access Via Roles video, I feel that almost 70% of the content within is either misleading or simply inaccurate.

Note: I spent significant time staging test cases in an org before deciding to write this blog post, so please let me know if any part of my writing is technically wrong.

2:10 Three ways to open up access? Not quite...


In the AW Computing scenario, the presenter says that access to private Opportunity records can be opened up in one of three ways, quoted below:
  • "No access. In essence, this maintains the org-wide default of private. Users in this role would not be able to see opportunities that they do not own."
  • "View only. Users in a role can view opportunities regardless of ownership."
  • "View and edit. Users in a role can view and edit opportunities regardless of ownership."

This sounds good in concept, but as the video progresses to the demo portion to show how the three ways are actually implemented, the problem becomes clear. The presenter is actually misconstruing and wrongly explaining the Opportunity Access options.

In reality, the implicit access granted through the role hierarchy automatically solves the requirement presented in the video, and the Opportunity Access options are completely irrelevant to the hypothetical situation.

A more accurate explanation


Let's assume that the role hierarchy is set up as implied by the visual at 1:40 in the video.



Alan can see and edit whatever opportunities Karen and Phil can see and edit. The two reasons are that Alan is above Karen and Phil in the role hierarchy, and that OWD for the Opportunity object is configured to grant access using hierarchies (which as of Spring '15 you still cannot disable for standard objects). There are no more granular controls for records owned within a subordinate chain. If Karen can see a record, Alan can see that record. If Karen can edit a record, Alan can edit that record. Access via subordinates in the hierarchy is that simple.

So what do the Opportunity Access options do? Simply put, the options do exactly what the Role Edit page says they do.


Opportunity Access options have nothing to do with roles and subordinates. The selected option comes into play in situations, such as ones involving account teams, where a user from one branch in the role hiearchy owns an account, but a user from a different branch owns an opportunity for that account.

Try it yourself


Admittedly this will be really difficult if you don't have access to a sandbox org or a Partner Enterprise Edition org, but here's the idea.

Your role hierarchy looks something like the following:
  • CEO
    • SVP Products
      • Product Sales Manager
    • SVP Services
      • Services Sales Manager

Configure Opportunity Access for all roles in the hierarchy so that "users in this role cannot access opportunities that they do not own that are associated with accounts that they do own."

Set OWD for Opportunity to "Private", then do the following:
  1. Log in as a Product Sales Manager
  2. Create an account
  3. Create an opportunity
  4. Log in as a Services Sales Manager
  5. Verify that you cannot see the opportunity
  6. Create a new opportunity on the account owned by the Product Sales Manager
  7. Log in as the Product Sales Manager
  8. Verify that you cannot see the new opportunity created by the Services Sales Manager
  9. Log in as the administrator
  10. Change the Opportunity Access for the Product Sales Manager role so that "users in this role can view all opportunities associated with accounts that they own, regardless of who owns the opportunities."
  11. Log in as the Product Sales Manager
  12. Verify that you can now see the new opportunity created by the Services Sales Manager
  13. Verify that you you cannot edit that opportunity

Saturday, May 30, 2015

The Apex Ten Commandments (in Writing)

For anyone (like me) who couldn't find the slides to The Apex Ten Commandments recording referenced on the Architect Core Resources page, here's the written list:

  1. Thou shalt not put queries in for loops
  2. Thou shalt not put DML in for loops
  3. Thou shalt have a happy balance between clicks & code
  4. Thou shalt only put one trigger per object
  5. Thou shalt not put code in triggers other than calling methods and managing execution order
  6. Thou shalt utilize maps for queries wherever possible
  7. Thou shalt make use of relationships to reduce queries wherever possible
  8. Thou shalt aim for 100% test coverage
  9. Thou shalt write meaningful and useful tests
  10. Thou shalt limit future calls and use asynchronous code where possible

And I just have a couple of comments to add for color.

Comments on #7


I haven't tested this hypothesis yet, but... does this commandment still hold with large data volumes? Especially in the context of batch Apex? One certainty is that executing a single query like this is convenient for the developer. But when the query would return thousands of records that reference a small set of parent records, perhaps at larger data volumes a more efficient approach would be to split the query and leverage commandment #6 instead.

Comments on #10


The future annotation is slowly become obsolete with the introduction of the Queuable interface in Winter '15, although general guidelines for designing asynchronous automation still hold true.

Monday, May 25, 2015

Force.com Query Optimizer FAQ (cont'd)

The webinar, Inside the Force.com Query Optimizer delivered in April, 2013 is still featured as a relevant resource on the Architect Core Resources page. While the webinar explains many key considerations for designing queries, many questions linger. Let's take a closer look at these open questions, and let me know if you have any of your own to add!

Why does query optimization affect me as an admin? I don't write code.


If I were a betting man, I would bet that under the hood, SOQL queries, reports, list views and related lists on detail pages all tap into the same query execution framework. So, if you manage page layouts, reports and/or list views, you should care about the Force.com Query Optimizer.

What is a selective query?


A selective query is a query that leverages indexes in filters to avoid full table scans and to reduce the number of records in your result set below the selectivity threshold.

Stupid question, but what is an index?


This is a great question. Simply put, an index is a field-based mechanism by which a query can execute significantly faster, compared to execution without the index. Salesforce technical architects don't need to know how an index actually works behind the scenes, much like office workers don't need to know how a Keurig machine makes coffee at the press of a button.

A technical architect probably just needs to know that fields are either indexed or not indexed, and that indexed fields should be used in query filters. The technical architect should probably also know off-hand what standard indexes are available, and that custom indexes have lower selectivity thresholds and can only be created by Salesforce Support.

Anyone hardcore enough to dig into the Oracle database-level index machinery may want to check out the Database Systems course, offered gratis through MIT OpenCourseWare.

What's considered a standard index?


Great question! I wasn't able to find concrete documentation on this question, so you tell me (on Twitter)! I think an official answer would be a welcome addition to the "Force.com Query Optimizer FAQ" article. In the meantime, the list of indexed standard fields can be considered to all be standard indexes.

What is the selectivity threshold? And why should I care?


The selectivity threshold is the maximum number of records that can be returned in a result set, without disqualifying the index-based optimization option for a query. See the Query & Search Optimization Cheat Sheet for the exact calculations used with standard indexes and custom indexes.

Is there a difference between using nested queries vs. separate queries?


This was the first question asked on the Inside the Force.com Query Optimizer webinar during Q&A, "Is using nested queries good practice?" But I don't think the answer fully addressed the question. My personal guess (which needs to be validated in an org that actually contains large data volumes) is that nested queries have negligible impact on the execution time of a query, as long as the queries are not constructed in a way that uses the NOT operator.

The basis for my conjecture is a best guess that nested queries are executed sequentially, following an order of operations that allows the result set from one query to be used in another query. How true is this? I suppose I'll need to test all of the following query structures with selective filters applied:
More importantly, however, it's worth noting that in some instances executing separate queries in Apex is unfeasible, and the only viable alternative is to use nested queries. I could be wrong (and please correct me if I am), but one such situation could be an Apex method that needs to iterate through a result set using a for loop, processing child records for each record returned.

Sunday, May 17, 2015

Exchange Sync [sic] vs. Salesforce for Outlook

There's an intentional mistake in this Summer '15 post's title: The true comparison is between Email Connect and Salesforce for Outlook ("SFO"), not between Exchange Sync and SFO. If you are currently confused by Email Connect vs. Exchange Sync like I used to be, read on.

Basically, there are two key capabilities desired in any Salesforce-Outlook integration:
  • Record synchronization. Contacts, events (i.e., appointments and meetings), and tasks should be synchronized between a user's Salesforce experience and his Outlook experience.
  • Easy access to CRM data. A user working within Outlook should be able to easily look up records in Salesforce and to attach emails to those records.

Email Connect and Salesforce for Outlook take different approaches to implementing those two capabilities.

Email Connect Salesforce for Outlook
Record Sync Exchange Sync, which uses a service account on Exchange Server and simple configuration in Salesforce to enable fast, auto-magic synchronization to and from any app or device that connects to Exchange Server Salesforce for Outlook service, which must be running in the background on a user's local machine. This means that as soon as the machine is shut down or put to sleep, sync stops completely.
CRM Data Access Salesforce App for Outlook, which produces an interactive side panel in Outlook, using the new apps for Office platform. Using the apps for Office platform means that this app can look and feel native, without a user needing to actually download or install an add-in on his local machine. Salesforce Side Panel add-in, which is an add-in that must be installed on a user's local machine and and then enabled in Outlook
Software? No! Yes, Salesforce for Outlook

While the Salesforce App for Outlook is still being developed to meet and then exceed the capabilities of the currently GA Salesforce for Outlook add-in, admins can actually get the best of both worlds by mixing the two solutions. An admin can implement Exchange Sync (Beta) and still use the SFO add-in, with the SFO sync functionality turned off. This possibility is critically important for organizations that are using an older version of Exchange Server that doesn't support apps for Office.

In short, Email Connect is the true alternative to Salesforce for Outlook. And the long-term vision for Email Connect seems to be a no-software solution that not only syncs contacts, events and tasks, but also gives users an interactive side panel for easily working with Salesforce data directly within Outlook.

Incredibly, "no software" implies that all this to be achieved without the user having to install a single piece of software. Boom!

Tuesday, May 5, 2015

4 Warning Signs You’re Spamming, Not Sharing

A poll recently appeared about whether sharing blog posts to multiple groups within the Salesforce Success Community constitutes spam. Behind that poll was a lengthy conversation and another poll, where opinions seemed to be split 50-50 between "yes, cross-post freely" and "no, keep it contained in an opt-in channel". So, if I write a piece about best practice for regression testing in Salesforce, and in my excitement I want to share that piece with others on the Success Community, am I sharing or am I spamming? (For the record, the piece I mentioned is hypothetical. I haven't written any such piece to date.)

There's a fine line between sharing for the good of a community and spamming the community in self-promotion (intentional or not). And as a professional consultant, I try very hard to walk that fine line without crossing into spam territory.

The 4 warnings signs below highlight my views on what's spam and what's not.

1. Your post promotes a product or service


When starting a new thread of discussion with a new post, consider whether the content you're sharing mentions a specific paid app from the AppExchange or highlights the success of a specific consulting company. If so, chances are people are going to feel like you're spamming.

I do want to highlight a difference between posting new (unsolicited) instead of responding to a question or an explicitly expressed need (solicited). In the latter case, you could actually be helping by pointing the other person to a solution, paid or otherwise, that really addresses the need.

Consultant's note: Sometimes I come across a question on the community that seems like a lead for a new project at a prospective client. Personally I do still take time to answer the question in as much detail as I think is feasible, so that the poster has enough guidance to either implement the solution on his own or to contract a partner to help. Posting bluntly, "you need a partner to help" would be inappropriate.

2. You blindly cross-post your blog across multiple groups


With Chatter, it's super easy to share a single post across multiple groups, either by sharing (i.e., reposting) the original post or by mentioning other groups in a comment. If you're simply cross-posting without assessing and repackaging the content to make it relevant to each new audience, chances are you're spamming.

Consider for example a notification about an MVP Office Hours conference call, offered free of charge to the community. People share this information with their local user groups, and generally speaking no one complains about this being spam, because the resource is relevant and targeted to users, who are naturally members of user groups.

But is the same notification appropriate for an official group that's created specifically for a feature or different topic of interest, such as the Salesforce1 group or the Communities Implementation group? Now the cross-post is starting to smell like spam, unless additional context can be provided to explain that there will be a dedicated segment to mobile apps or Communities.

3. Your post has no clear relevance to the audience


Take a look at the charter or description of a group or any channel, and assess whether your post has relevance and value to add to that group. Obviously if the value is unclear or loosely associated, your post is probably spam. But I think it is possible to tweak or augment a post with additional information to make it relevant to a new audience.

Let's use Lightning Process Builder as an example in the context of Salesforce. A generic statement that adds unclear value could be, "Process Builder is the future of declarative automation on the Salesforce1 Platform." Posting this as-is to a Sales Effectiveness group is probably a bad idea. But adding additional context could make the post relevant, such as, "Here's an example of a process that intelligently populates the Next Step field with a recommended action based on field values on the opportunity and account."

4. You have no prior relationship with the audience


This one should be a no-brainer. Did you join a group or cross-post to a group just to share a piece of content? Even if you're doing it with the best of intentions, your action could be seen as spam. This is a human consideration, not necessarily a technicality.

Closing thoughts


Use common sense. None of the signs above are hard and fast rules. But instead, think of them as factors that comprise a "contributor score" similar to a Sender Score. Reputations are difficult to build and easy to ruin, so don't lie to yourself about what you're trying to do.

Treat your audience as real people, and imagine you were telling each person individually about whatever content you're about to share. If you think the vast majority of people will be appreciative, go for it. If not, you should probably err on the side of caution.

P.S. At the risk of being seen as promoting religion, I also want to share Matthew 18:15-17. This is 5 sentences well written about conflict resolution that applies to resolving differences of opinion about what is and isn't spam.

Wednesday, April 15, 2015

Salesforce Security & Visibility Design Considerations

I felt compelled to create a Salesforce Security & Visibility Design Considerations matrix to synthesize and expand on the information presented in the Design Considerations training module, part of the Building Applications with Force.com - Part 1 course. We already have a similar template internally in my company, but creating one from scratch and adding to it on my own feels like a good way to internalize the knowledge.

The matrix focuses on two aspects: object security and record visibility. Specifically, who has permissions to do what with each object, and who can see what records in each object.

To control the "doing", the most straightforward way is to use object permissions with profiles and permission sets. However, it is conceivable that less admin-friendly and user-friendly options can be used to prevent certain operations. Below are a couple of examples:

  • A validation rule can be used to prevent editing closed opportunities
  • A Process Builder process could fire an autolaunched flow that reaches a fault condition, causing the create or edit operation to fail. Although I doubt anyone would do this right now, not only because it's cumbersome to implement but also because the error presentation in Spring '15 is not very pretty.
  • An Apex trigger can be used to add errors to a record, thereby preventing the create, edit or delete operation

To control the "seeing" of records, the only practical means are to use the role hierarchy, teams (where applicable) and sharing rules. However, I do want to point out one technically possible way to restrict visibility in the UI, and that is to use Visualforce page overrides for standard actions. A Visualforce page could use the init action to route the user to a different page based on record and user criteria. While in theory the approach would work, in practice the override would fall flat because of incompatibility with Salesforce1 and because users can create reports or list views to see the "hidden" records.

Friday, December 12, 2014

Workflow rule to record prior Owner Name

Sometimes you want to record a prior (a.k.a. "old") value for a particular field when it changes. If you need this simply for auditing purposes, tracking field history or implementing feed tracking should be all you need. But an alternative is needed if you want to do something else with that prior value, such as presenting it on a report or using it in a formula field.

The easiest way to record the prior value for something like Owner ID (could be Lead, Account, etc.) is to create a workflow rule and field update that uses the PRIORVALUE() function.

To see this in action, try the following to store the prior Lead Owner ID:

  1. Create a Text(80) field on the Lead object named PriorLeadOwnerId
  2. Create a workflow rule named, "Set Prior Lead Owner ID". For evaluation criteria, select "Evaluate the rule when a record is created, and every time it’s edited". For rule criteria, enter this simple formula: ISCHANGED( OwnerId )
  3. Add a new field update action to the workflow rule named PriorLeadOwnerName, which updates the Prior Lead Owner Field by setting it to the formula: PRIORVALUE( OwnerId )
  4. Activate the workflow rule

Tip: If you want store prior related values, such as Owner Name instead of Owner ID, you can actually use a formula field to work around a PRIORVALUE() limitation.

For example, you can create a formula field labeled Lead Owner Name with formula, BLANKVALUE( Owner:Queue.Name , Owner:User.FirstName + ' ' + Owner:User.LastName ), and then use this formula field in the above workflow rule instead of OwnerId.


At this time, workflow rules still cannot set a Lookup field to a dynamic or formulaic value. So while a workflow rule certainly is convenient, it's important to remember that in Winter '15 there are a couple of other more powerful alternatives. 
  • Lightning Process Builder: Beta feature that seems poised to replace workflow rules once it becomes GA.
  • Apex triggers: Nothing quite beats the power and precision of an Apex trigger, But you will need to learn some new syntax and guidelines.

Tuesday, December 9, 2014

Checkbox field for Live Agent pre-chat form

A [simple question](http://salesforce.stackexchange.com/questions/58529/live-agent-pre-chat-api-custom-checkbox-field/58533#58533) on Salesforce Stack Exchange exposed some unexpected behavior with the Pre-Chat API: Checkbox fields cannot be included as part of the pre-chat form.

The behavior appears to be that if a checkbox field is added to the specification for liveagent.prechat.findorcreate.map and liveagent.prechat.findorcreate.map.doCreate, the creation process fails and the desired record is not created. As soon as the checkbox field is removed from the form definition, the record creation process executes as expected.

While the reason for this behavior is unclear, at least there are two possible workarounds. The key to both workarounds is knowing that the String value of a marked checkbox is "on", and the String value of an unmarked checkbox is blank or null.


Workaround 1: Workflow rule


Assuming you've already created your Checkbox field, you can create a complementary Text field to hold the checkbox value submitted through the pre-chat form. For example, let's say your Checkbox field is named IsEmployed__c. You can create a Text field named IsEmployedText__c, and bind the pre-chat form field to IsEmployedText__c.

To close the loop, you'll create a workflow rule that basically sets IsEmployed__c to true when IsEmployedText__c equals "on", and another workflow rule to set IsEmployed__c to false otherwise.

Workaround 2: Formula field


Start with a Text field, and then simply create a Formula (Checkbox) field that uses NOT( ISBLANK( __ ) ) to produce the equivalent Boolean value.

For example, create a Text field named IsEmployedText__c, and bind the pre-chat form to this field. Within Salesforce, create a Formula (Checkbox) field named IsEmployed__c, and put int he formula NOT( ISBLANK( IsEmployedText__c ) ).

Wednesday, December 3, 2014

Where are my Featured Search images in Kokua?

If you're trying out the new Community Designer feature (in beta still, as of Winter '15), you may run into a bit of trouble getting the images to appear correctly for Featured Search on Kokua's homepage. At a high level, there are the three key requirements to getting an images to appear on the homepage, explained in more detail below.

  • Name the image as DataCategoryUniqueName-s.jpg
  • Upload the image as an asset using Site.com Studio
  • Enter a value using merge fields into the Category Image URL: {!Global.PathPrefix}/{!DataCategory.Name}.jpg

Note: The ".jpg" extension is not required, but it must match what you entered for the Category Image URL.

Name the image


To figure out what to name an image for a data category, you need to know the data category's Category Unique Name is. To figure this out, first go to Setup > Customize > Data Categories > Data Category Setup. Next, click the Actions button next to an existing data category, then click Edit Category. Now the Category Unique Name field and value will be exposed.


For the Featured Search box on the homepage, you need to specify 's' (stands for "square") for the <size> portion of the filename. Here are some examples.

Examples of image filenames for Featured Search
Data Category Unique NameImage TypeImage Filename
Technology_EnablementJPEGTechnology_Enablement-s.jpg
Customer_EngagementJPEGCustomer_Engagement-s.jpg
StrategyPNGStrategy.png

Note: The Winter '15 documentation for Featured Search says that you should use the convention <datacategoryname>-<size>.<filetype>. However, a more accurate convention is <datacategoryuniquename>-<size>.<filetype>.

Upload the image


This part is relatively simple. All you need to do is open Site.com Studio for the community's site, and then upload the image as an asset.

  1. Go to Setup > Customize > Communities > All Communities
  2. Click Community Designer next to your community
  3. Click the top header's picklist next the the word "Communities", and click Go to Site.com Studio
  4. In the left-hand navigation tree, click Assets under All Site Content
  5. Click the Import... button, and upload your image


Note: If you upload a .zip file where the images are stored in folders, you will need to tweak your Category Image URL in the last step.

Enter a value for Category Image URL


Finally, while you're in Site.com Studio, you need to edit the main page and enter a value for the Category Image URL property in Featured Search.
  1. On the Overview tab, click Site Pages under All Site Content
  2. Double-click main under Site Map to open the page
  3. In the Views section, double-click Kokua Home to edit the view
  4. Under Page Structure, click Featured Data Categories
  5. In the Property Editor in the right sidebar, enter this exact value for Category Image URL: {!Global.PathPrefix}/{!DataCategory.Name}.jpg


Note: In the previous step if you uploaded a .zip file where the images are stored in folders, you need to include the folder names in the Category Image URL value, such as: {!Global.PathPrefix}/folder/subfolder/{!DataCategory.Name}.jpg

Sunday, November 9, 2014

Add, edit and remove parent and child records in Lightning component

After figuring out that I could leverage indexVar and custom data-* attributes to efficiently remove items from a list in Lightning, I decided to see whether the same component pattern could be applied to enable dynamic management of lists at a parent object level and at a child object level.


In the screenshot above (please excuse the ugly styles), the behavior is such that when a user clicks Edit for an account, the list of contacts changes to show only contacts for the selected account.

The basic building blocks of this app are the ns:manageAccounts and ns:manageContacts components, added to the Lightning application as follows:


And within both components, the following pattern is used:


The above concepts are simplified in their illustration, as the full setup also uses several custom events and event handlers. Please take a look at the oneAccount.app repo on GitHub for the full source code behind the sample app.

Lightning really appears to makes dynamic UI updates really simple for the developer, similar to other frameworks like Knockout. The real benefit of Lightning is that it's built directly on top of Salesforce, and as a result makes it easy to leverage the power of Apex in your apps and components.

Friday, October 31, 2014

Simple Lightning-to-Lead tutorial for the Salesforce1 Platform

If you're brand new to Lightning on the Salesforce1 Platform, and you're having a bit of trouble following the cool but relatively complex Expenses sample app from the Lightning Components Developer's Guide, maybe this Lightning-to-Lead tutorial will work better for you.

The goal is simple: Create a one-page app that basically does what Web-to-Lead does, which is to create a new Lead record. Nothing glorious, but it's just complicated enough to go over some core concepts. When you're done, you'll end up with a simple page with a few fields and a lone button.


Sound simple? Give it a try and let me know what you think!

Friday, October 10, 2014

Invalid apex:attribute name values

The apex:attribute component in Visualforce allows developers to pass custom Apex class instances as attributes from the parent component or page to the child component. In this manner, it's possible to pass a page controller itself as an attribute to a component on the page, using a simple self property like the following.

public CustomController getSelf() {
    return this;
}

What the documentation doesn't say is that apparently (at least in Winter '15, API 32.0) there are keywords to avoid when naming your attribute, even though the Visualforce parser will not tell you there's a problem.

Trying to name your attribute "controller" will cause something like the following error to appear when saving a page: Wrong type for attribute &lt;c:buggersitepaypalcheckout controller=&quot;{!self}&quot;&gt;. Expected BuggerSiteSimpleSelfRegController, found String



Trying to name your attribute "parent" will cause a completely blank error message to appear when saving a page. But it's an error that will prevent you from saving your page, nonetheless.



Do you know any other hidden no-no's with naming apex:attribute elements? Please share so that we can all avoid these frustrating quirks int he future.

Monday, September 22, 2014

Your request cannot be processed at this time. The site administrator has been alerted.

In setting up and testing self-registration for a new community built on Salesforce Communities, you may encounter this confounding error: "Your request cannot be processed at this time. The site administrator has been alerted."

"Alerted" in the above statement refers to an email alert that went out to the site administrator. But who is the "site administrator"? You can find the email address used for this notification by locating the Site Guest User for your community's Force.com site.
  1. Open Setup > Manage Communities
  2. Click Force.com for the community in question
  3. Click Edit
  4. Change Site Contact to the user who should receive notifications when errors arise with self-registration. Make sure the user's email address is valid.


For sandboxes, make sure your Access to Send Email is set to "All email", under Setup > Email Administration > Deliverability. (Thanks Lynnet!)


Below are a few common reasons why you may be encountering the problem:
  • The community is not published. In case you're working with a community that is offline or in Preview status, you need to publish the community before self-registration will work.
  • The Account Owner does not have a User Role assigned. If you're creating a new Account record on the fly, especially in B2C situations, you need to make sure you assign a default account owner that also has a User Role value. Any role will do, and you can use either a workflow rule or Apex to perform the assignment.
  • The site guest user does not have Create and Read permissions on the Account and Contact objects. Edit Public Access Settings for the community's Force.com site to grant these permissions, along with field permissions for any fields that are included on the self-registration form. Note that by default the site's profile will not have these permissions.
  • Self-registration is not enabled for the community. Go to Manage Communities, click Edit and make sure the Login settings show that self-registration is enabled.

For more details on setting up a community for self-registration, please refer to the Getting Started with Communities guide.

Friday, August 8, 2014

Created By and Last Modified By not set before insert or update

After some frustrating troubleshooting of what I thought would be simple code today, I learned something unexpected: Created By and Last Modified By are not populated or set in the before context of DML operations. This means that before insert, CreatedById, CreatedDate, LastModifiedById and LastModifiedDate are all empty. And before update, LastModifiedById and LastModifiedDate will reflect the previous person to modify the record, not the current user (which would be yourself if you are the one editing the record).

While this was counter-intuitive at first, I came to realize that there's no need to rely on those fields in the context of Apex triggers. All I really need is UserInfo.getUserId() and DateTime.now() to get the time.

Just like that... I learned something new today.

Tuesday, August 5, 2014

Person Accounts ignore Contact workflow rules and triggers

Every once in a while I find myself discussing the pros and cons Person Accounts, and inevitably a question comes up about how Account and Contact workflow rules and triggers are impacted. The vague statement that precipitates the question usually goes something like this, "Turning on Person Accounts creates problems for existing workflow rules and triggers." Today I finally decided to explore the validity of this statement myself, and the results were... well, disappointing.

The good news is that turning on Person Accounts will not break any of your existing functionality regarding Business Accounts and Contacts, as long as your Apex code is not automatically creating Contact records for accounts to emulate a one-to-one Account-Contact model.

The bad news is that none of your Contact workflow rules and triggers will fire for Person Account records. To me, this is a problem and poor design of the Person Accounts feature. Admins should at least be given the option to configure, perhaps via a checkbox, whether Contact workflow rules and triggers will fire for Person Account records. But as it currently stands, all benefits from existing Contact workflows and triggers are lost for person accounts.

If you agree with why the above bad news is bad, please promote this idea, "Person Accounts to work with Contact workflows and triggers." And read on if you want to know how I arrived at the above conclusions, which were tested in an Enterprise Edition org with Person Accounts enabled.

Test Setup (Summer '14)


The tests makes use of the following Text fields, for which history tracking is turned on:

  • Account Trigger Message (Account field)
  • Account Workflow Message (Account field)
  • Contact Trigger Message (Contact field)
  • Contact Workflow Message (Contact field)
To interact with those fields, we'll create two triggers and two workflow rules that simply set values for the implied fields on the Account and Contact object.
  • SetAccountTriggerMessage (Account trigger)
  • Set Account Workflow Message (Account workflow rule)
  • SetContactTriggerMessage (Contact trigger)
  • Set Contact Workflow Message (Contact workflow rule)
Now, with the stage set, let's move on to the tests.

Test 1: Create a person account


What happens when we create a person account?  Account workflow rules and triggers fire, but Contact workflow rules and triggers do not.

Test 2: Update an Account-only field on the person account


What happens when we update the Website field? Account workflow rules and triggers fire, but Contact ones do not.

Test 3: Update a Contact-only field on the person account


What happens when we update the Birthdate field? Oddly enough, Account workflow rules and triggers fire, but Contact ones do not.

Test 4: Update a special Account-Contact field on the person account


Knowing that the Account Name is linked to First Name and Last Name for Person Account records, what workflows and triggers will fire when you edit First Name or Last Name? Once again, Account workflow rules and triggers fire, but Contact ones do not.

Workaround for Contact workflows and triggers


The only supportable way to get Contact workflows and triggers to fire for Person Account records seems to be to recreate those workflows and triggers on the Account object. Whether this workaround is a pro or a con depends on your point of view. Obviously this creates more work and maintenance, but it allows for more granular and logical control over what happens with Contact fields for a person account vs. a regular contact.