Wednesday, July 21, 2010

About defaults, picks, maps and SetField events

That is an eclectic list of things in the title, and no I do not intend to talk about them all in detail other than to discuss a bit about how they interact and some of the design implications they may cause. So let me start with another list:
  • Pick Maps do not cascade
  • Fields set by a pick map cause a SetFieldValue event
  • Defaults do not cause a SetFieldValue event
  • On Field Update Set BC User Prop will trigger a SetFieldValue event
  • SetFieldValue event triggers a Pick
  • Setting a field to itself does not trigger a SetFieldValue event
So those are the important findings I had to deal with when implementing a seemingly simple requirement. My client had a contact type and sub type. The contact type should be denormalized from the related account's type. Finally, they want to set the contact sub type dynamically to a different value depending on the contact type. By dynamically, I mean not hard coded, so it can be changed without a release.

Let me put all that in functional terms by providing an example. The Account Type has a static LOV with values 'Bank' and 'Government'. The Contact can potentially be created as a child of an account, inheriting information from the account record, and triggering Parent expression default values, or can be created from the Contact screen without an account, but with the option to set the account later. When an account is specified for a contact, the contact type will be set to match the account type, otherwise the contact type should be set to 'Other'. If the Contact type is 'Bank', the contact sub type should get set to 'Retail', and if the contact type is 'Government', the sub type should be set to 'HUD'. So the basic configuration we started with was to put the desired 'dynamic' sub type value in the Low column on the LOV table. Then set up the pick map for contact type as such:

Field Picklist Field
Contact Type Value
Contact Sub Type Low

It would be convenient to just set the pick map similarly on Account Type as:

Field Picklist Field
Account Type Value
Contact Type Value

But the first rule above states this will not work because pick maps do not cascade. This makes some sense as you could conceivably end up with some circular logic. Or in the case where the contact is created as a child of an account, to predefault the Contact Type to the Account Type. But again, according to the rules above, a predefault will not trigger a SetField and hence no pick map.

So in order to trigger the pick map on Contact Type, we need to trigger a SetFieldValue event on this field. What to do. Oh, and I did not want to use script. My solution had a couple of dimensions.
  1. When a contact is created on the Contact Screen and the account is picked, I am going to trigger a set field value on the Account Type by creating a joined field on the Contact BC called Account Type, and add this field to the Account pick map. So this will trigger my SetFieldValue event. I then will add an 'On Field Update Set' BC User property to the Contact BC so that when the joined Account Type field is updated, set the Contact Type to the Account Type. Using a User Property will then trigger the SetFieldValue event on Contact Type which will then trigger the pick map to set the Contact Sub Type. So far so good.
  2. My approach on the scenario when a Contact is created as a child of an Account is not as clean. The problem here is that Predefaults do not trigger SetFieldValue events. And in this case, all the account information will already have been set via Predefault so there is no field being explicitly set by a user to trigger the User property. So I had to get creative. What I did was similar to above but placed identical user properties on Contact First and Last name fields. Since these are required fields that are typically entered first, they will trigger the user properties to set the contact type and sub type. In order to minimize the UI impacts of this admittedly kloogy design, I wanted the visible Contact Type in the applet to default correctly to the Account Type from the parent record. This means that when the User sets the First Name (or the Last) the Contact Type will already have the correct value so the User Property would essentially set it to itself. The last rule above states this will not trigger the SetFieldValue event. To get around this I create two User Properties in sequence, the first to set the Contact Type to null, and the second to set it back to the Account Type. Because I am putting the properties on both the First and Last name (to accommodate different user's field population sequences), I also want to add a conditional to the user properties to not execute if the Sub Type has already been set.
What does all this leave us with? In addition to the pick map on the Account field mentioned first, here are the On Field Update Set user properties on the Contact BC:
  1. "Account Type", "Contact Type", "[Account Type]"
  2. "First Name", "Contact Type", "", "[Contact Sub Type] IS NULL"
  3. "First Name", "Contact Type", "[Account Type]", "[Contact Sub Type] IS NULL"
  4. "Last Name", "Contact Type", "", "[Contact Sub Type] IS NULL"
  5. "Last Name", "Contact Type", "[Account Type]", "[Contact Sub Type] IS NULL"
I am going to leave it there, but this actually gets even more complicated. Because a contact can be created from a pick applet from a service request, I also had to account for predefaulting the account to the SR's account and this impact this would have on predefaulting Contact Type and Sub Type. If anyone would like to see how this is done, here is where to start.

No comments:

Post a Comment