MT-ing My Head

Welcome to my soapbox of Salesforce technical writing, music, and miscellaneous stuff

Music Musings: Cam – “The Otherside” — November 10, 2020

Music Musings: Cam – “The Otherside”

More people should know about Cam. There, I said it. And she introduced herself on Twitter better than I ever could:

Cam’s song “Burning House” got popular in 2015. The beautiful acoustic ballad was versatile enough for both the country stations and Light FM.

In general, however, airplay has been dismal (which is not surprising for women in country music…different conversation.)

That being said, want to use my (somewhat limited) platform to amplify. Cam’s new album The Otherside is EVERYTHING:

  • Adorable (“Classic”)
  • Bittersweet and Nostalgic (“Forgetting You”, “Redwood Tree”,”Happier for You”,”Changes”)
  • Catchy (the whole darn album!)
  • Complex in storytelling (“Diane”, a response to Dolly Parton’s “Jolene”)
  • Deep and inspirational (“Girl Like Me”)
  • Musically complex (“The Otherside”)
  • Musically varied (the whole album… “What Goodbye Means” stuck out to me because of ABBA vibes)
  • Romantic (“Like a Movie”, “Till There’s Nothing Left”)

And she has *PIPES*, man. Her voice is silky and distinct.

Also she is the sweetest person from the limited paid interaction I had with her…

Meeting Cam at Hammerstein Ballroom in 2015. I miss concerts! 😥

Listen to The Otherside on Spotify here:

Saving Money with Visualforce Templates — November 9, 2020

Saving Money with Visualforce Templates

Business Problem

My organizations has partnerships with different online education vendors such as Ukueoke, Fender Play, and MasterClass. These companies provide us with In Kind Donations of access codes. Our constituents can then request codes.

In the past, people had requested one code at a time.

However, a unique issue came up in 2019 when a vendor donated 8,000 codes, and constituents could apply for an unlimited number of codes. One person requested over 300!

We needed a way to send teachers codes in a way that would not mean sending, like, a billion emails.

My first attempt at solving this was to build a system in Flow that automatically assigns codes to Contact (more on that in at another time). Then, I created a Conga template that printed all of the Special Codes related to an application.

I needed to use Conga Conductor to send these out in mass (at one point we had about 400 to send out.) This got expensive at ~$1.00 per send.

Data schema spaghetti :-)~

How I Solved It

Using this blog post as a guide (like, amazing? THANK YOU), I went to play in my Sandbox. I created three components:

  1. An Apex Controller
  2. A Visualforce component
  3. A Visualforce email template

Da Controlla

A controller allows us to use code in email templates and Visualforce pages.

NSFW probably?
public class SpecialCodeController

## Gives the thing a name

{
    public Id teacherAppId {get;set;}

## Gives the Teacher Application record a place to live called TeacherAppId and sets permissions/says "welcome!"

    public List<Special_Codes__c> getCodeList()

## Creates a cradle for the baby codes

    {
        List<Special_Codes__c> codeList;
        codeList = [SELECT Name, Type_of_Code__c, Code_Expiration_Date__c, MasterClass_Code__c, FourChords_Code__c FROM Special_Codes__c WHERE Teacher_Application__c =: teacherAppId ORDER BY Name ASC];
        return codeList;
    }
}
##Adds the baby codes to the codeList. We know they're the right ones because of the WHERE clause which references the teacherAppId variable above! Cool!

Visualforce Component

A Visualforce Component takes the code from above and makes it usable! It’s like a widget according to this help article.

This Component is called specialCodeVis.

<apex:component controller="SpecialCodeController" access="global">
## References the controller above

<apex:attribute name="teacherAppIdVis" type="Id" description="Id of the Teacher App" assignTo="{!teacherAppId}"/>     
##Creates an attribute called teacherAppIdVis that references an ID to a Teacher Application that we will add later

<table border = "2" cellspacing = "5">
#This is a table created with in HTML. Brings me back to my Neopets days!
<tr>
<td>Name</td>
<td>Code</td>
</tr>
<apex:repeat value="{!codeList}" var="code">

##An apex:repeat iterates over a list. The variable for each Special Code in the query is "code". That's how we get this table to be dynamic.

<tr><td>{!code.Name}</td>
<td>{!code.MasterClass_Code__c}</td>
</tr>

</apex:repeat>
</table> </apex:component>                                      

Email Template

Finally, we can pipe the Visualforce Component into a Visualforce Email Template! Exciting!

    <c:specialCodeVis teacherAppIdVis="{!relatedTo.Id}" />
##OMG! This references the Visualforce Component and defines that the variable will be the {!relatedTo.Id}**

**Side note: I also learned that the “relatedTo.” tag in Visualforce email templates are a GREAT way to get merge fields many layers deep in an email template using dot notation :o) Good bonus from this project. However these templates can be pretty annoying to edit without admin privileges.

Final Product!

This is the Visualforce email template we built. The table is what we built with this code!
Thanks to our marketing team for providing 🔥 copy

Implementation Notes

  • I deployed the three items above from my Sandbox into production using a change set.
  • Make sure that the Security on the Controller is set so that anyone using the template (or is the running user on an automation that uses the template) is able to access it. After I deployed this, one of my users had a permissions issue and I had to add some profiles to the Controlla.

Conclusion

This will likely save us thousands of dollars in automations (For instance $1 per email x 5 partnerships x 500 emails per partnership = $2,500). It’s worth noting that I built the expensive solution to begin with, though. :’)

How I Fixed It: Duplicates of an Object with Two Lookups — November 8, 2020

How I Fixed It: Duplicates of an Object with Two Lookups

This is a series of posts about data cleanup in SalesforceThe goal is to IDENTIFY, FIX, AND PREVENT data issues.

The Problem

We created a custom object that relates Contacts with each other (“Relationship”) using two lookup fields (“Primary Contact” and “Secondary Contact”). Over time, a rogue form created up to 10 of the same record.

Business Implications

The duplicate relationships were frustrating to look at on the page layout for our users.

Additionally, they showed up when running reports and needed to be cleared in Excel before distributing.

Finally, it was unclear when the relationship was actually established in the system (earliest date).

What I Did

Identifying the Records

I created a formula field called “Primary and Secondary Contacts Same” on the Relationship object with the following formula:

CASESAFEID(Primary_Contact__r.Id) = CASESAFEID(Secondary_Contact__r.Id)

Then I created a report and grouped by this field and sorted by Record Count descending.

Fixing the Records

Due to the low number of duplicates, it was easiest for someone to manually go in and delete every record except the oldest. I could have also used Excel to identify which record to keep of each duplicate set.

Preventing the Issue Moving Forward

First, I tried to use a matching rule to detect records with the same values across two lookup fields (for instance multiple records with Bob in field 1 in John in field 2). Unfortunately, this was not possible! Sad!

After some Googling, I came across Gorav Seth’s method of preventing duplicates among junction objects. This includes creating a new field for a unique key, a before-update flow that updates the unique key, a matching rule, and a duplicate rule.

Screenshot 2020-02-08 at 7.40.06 AM.png
Screenshot from goravseth.com

Conclusion

This was a very simple solution that ultimately saved us money on a deduping tool that allows for deduping of custom objects!

How I Fixed It: Improperly Formatted Contact Names — November 7, 2020

How I Fixed It: Improperly Formatted Contact Names

This is a series of posts about data cleanup in Salesforce. The goal is to IDENTIFY, FIX, AND PREVENT data issues.

The Problem

We have a series of forms (for making a donation or signing up for a program, for instance) that create Contact records in Salesforce. Some people type in all caps (e.g. BOB ROSS) or all lowercase (e.g. bob ross) and the records end up reflecting that.

Business Implications

  • Merge Fields in Mailers – A mass email or appeal letter will end up saying “Dear bob,” rather than “Dear Bob,”
  • Reporting to Funders – When we need to report program data to funders on a granular (constituent-based) level, the development team has to spend time formatting the names properly before sharing the report.

What I Did

Identifying the Records

After some exploratory data analysis and trial and error, I created two checkbox formula fields on the Contact called “Contact First Name Bad Format” and “Contact Last Name Bad Format” (I know, I know…silly field labels).

First Name Field

AND(LEN(FirstName)>2,NOT(CONTAINS(FirstName,".")),
OR(FirstName=LOWER(FirstName),FirstName=UPPER(FirstName)))

Last Name Field

AND(LEN(LastName)>1,NOT(CONTAINS(LastName,".")),
OR(LastName=LOWER(LastName),LastName=UPPER(LastName)))

These formulas looks for Contacts with the First Name or Last Name in all uppercase or lowercase. It ignores initials such as “DJ” for first names or “C.” for last names. People putting initials instead of their full last names into fields is a different issue….

Fixing the Records

I ran a report of all of the Contacts where the “Contact First Name Bad Format” OR “Contact Last Name Bad Format” fields were true. I made sure to include the 18-digit Case-Safe Contact ID in this report.

Then I exported the report, used the PROPER() function on Excel to change the first and last names to proper formatting, and used Apex Data Loader to update these (400 or so) records.

Preventing the Issue Moving Forward

To prevent this issue from happening in the future., I created two workflow rules using the a) the criteria in the above formula fields and b) field updates witht he solution mentioned in this post.

This workflow rule will detect if a person’s name is in all uppercase or lowercase letters and edit it accordingly:

Criteria

See formula fields above

Evaluation Criteria

Evaluate the rule when a record is created, and any time it’s edited to subsequently meet criteria

Actions

  • Field Update: Update First Name (Proper)
    • Field: First Name
    • Code: UPPER(LEFT(FirstName, 1)) & LOWER(RIGHT(FirstName, LEN(FirstName) – 1))
  • Field Update: Update Last Name (Proper)
    • Field: Last Name
    • Code: UPPER(LEFT(LastName, 1)) & LOWER(RIGHT(LastName, LEN(LastName) – 1))

Testing the Workflow Rules

First I manually created Contacts with the above names:

Contact NameExpected Result
JJ AbramsJJ Abrams
AUDRE LORDEAudre Lorde
audre lordeAudre Lorde
F. FITZGERALDF. Fitzgerald

Other Tests

TestExpected Result
Edit Contact manually with one of above namesFix name
Fill out the donation form with one of the above namesFix name and send acknowledgement with fixed name included
Fill out a program form with one of the above namesFix name
YESSSS! It worked.

What’s Left to Do

Tweak the field update to be more precise – There’s still some room for error here, since the formula only capitalizes the first letter of each field. Some exceptions that this would not update properly would be:

  • Gordon-Levitt
  • McDonald
  • DiFranco

Conclusion

Overall, this took about two hours to figure out and will likely save more than two hours of annoyance and manual editing in the future.

Feel free to comment with any questions or other ways you’ve solved this.

My Solo Trip — November 6, 2020

My Solo Trip

Last weekend I took a solo trip to the Hudson Valley area in New York State.

I rented a room in a town called Ancram, with a view of the mountains through the sunny kitchen window. It was very remote; I asked the Airbnb host if there was any food delivery in the area and she laughed… ha.

I had never been up there before and didn’t know what to expect. I spent some time in Hudson, NY, a beautiful town on the Hudson River, and bought a yummy smelling candle there. The food was also delicious; I had Thai curry and a veggie burger. I also went for a 5-mile easy hike at Lake Taghkanic by myself! It was my first solo hike.

Solo travel is something I’ve grown to appreciate more recently, especially during the pandemic. I have often waited until I could find a travel companion to do things that I want to do, but I don’t think that’s realistic or helpful.

The best part of this trip was not pushing myself to be productive. One of the evenings it was very cold I stayed in bed and went to a knitting circle. I had lazy mornings and only went outside when I had energy to do so. I vowed not to have FOMO, and that helped. There was a lot to do up there – farms, wineries, etc. but I followed my intuition on what I wanted to do at each moment.

10/10 would recommend solo travel to a friend.

Reflections on Gender — November 5, 2020

Reflections on Gender

I was video chatting with a group of people and we were talking about blogging. Blogging is always on my list of “things to do when I have more time/energy,” but I never do it.

Questions like “How personal should I get online?” or “What if I want to write about many different things?” always put me into a state of analysis paralysis. So I want to start with just one post.

I have an ongoing list of good (or neutral) changes that have happened in 2020.

A few highlights:

  • Trying vegetarianism
  • Started talking on the phone more
  • Started making my bed
  • Started meditating
  • Coming to terms with my genderfludiity

Not going out to bars or dating for months allowed me to see how I naturally exist in the world, versus how I present to the world. I was taking a break from being perceived and from showing up in a way that I thought would attract others.

I often feel androgynous or masculine inside, but I have always hid it under hyper-feminine clothing. It creates a lot of cognitive dissonance, especially in a relationship context: I am treated like a feminine person but inside I feel differently.

Over the summer I had a bit of a revelation about gender followed by an anxious purge to get rid of my “girl clothes”. Some of it was clothing I wore in college in order to appear conventionally pretty and attract men in fraternities. It was bittersweet to leave those items behind. I said the Marie Kondo-esque “Thank you for letting me wear you” and sent them on their way.

But then there were certain feminine pieces that I feel comfortable in and wanted to keep.

This is where self-discovery gets complicated. I learned that I always want to “fit a mold” or live to match an extreme – which maybe got me into this hyper-femme “look” in the first place – and I am just not that simple. I decided to keep some of the feminine clothes. I feel comfortable in them, and I like them.

I ended up cutting my hair, which helped with my complex gender feelings a lot. I had medium-length hair and got it cut into a bob. This was perfect; I can make myself look more feminine when I want by curling my hair and putting on makeup, but my baseline “look” is androgynous.

The look kind of has this vibe:

Woman's bob
This is not me. It’s just a picture from Google.

Finally, I began to think about how presenting more masculine would affect my personality. What patterns of speech have I learned as a woman? Would that change as I show my masculine side more? What about ways of thinking and emoting?

What I found, overall, is that I don’t have all the answers. The only thing I learned is that I don’t need to be an archetype; I just need to live according to my values and more will be revealed.