MT-ing My Head

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

Progress Not Perfection, and Some Musings on Where This Blog Might Go — November 16, 2020

Progress Not Perfection, and Some Musings on Where This Blog Might Go

When I started this blog I decided to try writing every day for 30 days. I missed Sunday the 15th because I was out exploring a museum with friends and then on various virtual hangouts.

Then I delved into a new knitting project, a hat for my best friend.

This was all time well-spent I think.

Friends at the art museum 🙂 we had to book a time to go- it was like being VIPs and having the museum all to ourselves. Luckily we didn’t get locked inside so we weren’t there when the exhibits came to life at night.

In the past, my pursuit of perfection paradoxically caused me to fail (pardon my annoying alliteration). For instance, if I missed a post I developed a mental block and stopped. Or if my grammar was not perfect or the graphics were not beautiful, I would start to resent my work.

Today I have compassion for myself. Today I strive for a slow burn – a consistent stream of ideas with some margin for rest and focus on other things – instead of an explosion of energy and motivation followed by radio silence.

This evening I spent some time thinking about how my life has changed in the last year, what I have grown to care about, and, in turn, what I may want to write about. A few ideas that came to mind outside of Salesforce and nonprofit technology are:

  • Spirituality and my relationship to a higher power
  • Dyspraxia/neurodivergence and learning self-acceptance
  • Women in country radio – why aren’t there many?
  • Codependency and how it is engrained in our culture
  • The importance of moderation
  • Setting goals and rolling with the punches, how to balance
  • Self-care is doing laundry
  • Sometimes spending money is okay!
  • Procrastination
  • Cognitive dissonance: tech and border patrol
  • also maybe sharing some poetry?!

If any of these sound cool, do let me know and I’ll focus my attention on those topics first.

Reflections on My First Year Cooking — November 14, 2020

Reflections on My First Year Cooking

In January of this year, I decided to start cooking for myself. I honestly don’t remember how I fed myself before. Maybe lots of trips to the WholeFoods hot bar. Yeah, that checks out.

I had signed up for Workweek Lunch (WWL) months before. WWL is a subscription meal prep service that provides yummy recipes that are fridge and microwave friendly.

Around January, I finally decided to start using my subscription and learned how to cook a few basic meals including vegetarian stuffed peppers, fish tacos, and chicken tikka masala. These recipes taught me a few skills such as how to make lentils, how to cook fish, and how to cut meat uniformly.

A few learnings:

  • Meal selection
    • It’s okay to make super basic meals. My go-to during the pandemic was sautéed black beans with cumin and vegetables.
    • Find foods you like when you go out to eat and try to recreate them at home.
  • The act of cooking
    • Clean up as you cook.
    • Taste as you cook.
    • Read the recipe beforehand to understand what tasks are grouped together (cooking is basically project management)
    • Prep ingredients beforehand by cutting vegetables and measuring out liquids and spices. This makes cooking less chaotic.
    • Make everything twice. The first time, write out your learnings.

Cooking is one of the only tasks that completely engrosses my mind. I need to be present and focus on the task at hand, while being flexible and adjusting flavors.

Overall, working from home during the pandemic has been so helpful to my eating habits. I have been able to cook or reheat every meal and feeding myself has become a special self-care ritual.

I am thankful for this opportunity to work from home and have developed a new appreciation for food.

Mobile Giving: An Intro — November 13, 2020

Mobile Giving: An Intro

Today’s topic is mobile giving.

Mobile giving is an important tool for a nonprofit organization’s individual giving strategy. According to this article at Nonprofit Source:

  • 25% of donors complete their donations on mobile devices
  • 51% of people who visit a nonprofit’s website do so from a mobile device

etc.

Mobile giving can be separated into a few different areas, such as:

  • Text-to-Give/Donate (SMS Donations) – Texting a keyword to a phone number to give money. Both options are great for events, virtual and in-person alike.
  • Scan to Give – Scan a QR code that leads to a donation form.
  • Outbound SMS – SMS serves as a mass communication channel similar to email. It may convey information or have a call-to-action to donate. Retail stores often use this to give discounts and share sales.

Today, I am focusing on SMS Donations. In a future post, I may detail how one might set this up in Salesforce using an external (paid) tool.

Text-to-Give versus Text-to-Donate

When choosing a provider

Text-to-Give means texting a keyword to a phone number and the donation being added to your cellphone bill.

Pros:

  • Simple experience – one step and no forms.
  • Does not require Internet access, only cell service.
  • Presumably less cart abandonment since there’s just one step.

Cons:

  • Works in pre-determined small amounts, so giving capacity is limited.
  • Delay in receiving the funds.
  • Donor data can be sparse, may need to set up flows to get additional data later.
  • Can be costly – important to make sure there is ROI here.

Implementation Options:

Text-to-Donate means texting a keyword to a phone number and receiving a link to a mobile-responsive donation form via SMS. This form can be accessed via a browser.

Pros:

  • Richer donor data.
  • Can donate any amount.
  • Can get funds more quickly since they come in through a regular payment processor.

Cons:

  • Need to be connected to Wifi or use data.
  • More steps for the donor.
  • If the donor thinks that the functionality is like text-to-give, they may think that by texting, they have already made the donation. This can be remedied to some extent by writing clear copy, but there will always be people who are just not paying attention.

Options for Implementation:

  • Text-to-Give Software: Text-to-give software is available. We were impressed by Zoomgive.
    • Pro: Likely provides analytics, and attractive mobile-first donation forms. They know mobile-first best practices and are mobile-first.
    • Con: Requires integration with CRM. Also sometimes not a lot of room for form customization (e.g. adding tribute options). Finally, there are likely fees associated so the ROI needs to make this option “worth it”.
  • Salesforce SMS and Donation Form: Use an SMS provider (we had SMS Magic for other purposes) to create a keyword automation that sends donor a mobile-responsive donation form (we use Formstack right now)
    • Pro: Easy integration into Salesforce for donation logging, since you are using an existing donation form. Inexpensive.
    • Con: May need automation chops, depending on which SMS tool you use. Also can be clunkier than an out-of-box solution.
  • Another SMS tool and Donation Form – We once used Mobomix and our regular donation form. We purchased some SMS credits and a keyword for $10/month and were off to the races.
    • Pro: Inexpensive. Easy-to-implement tool. Includes short code (see caveats below).
    • Con: Sometimes you may not get the keyword you want. Also, you are sharing a short-code phone number with other companies.

A Quick Note on Short Codes

Short codes are 5-6-digit phone numbers like “55055”. They are very convenient for text-to-give and mass communication purposes, compared to long toll-free numbers like 1-888-230-1204. They are easier for the donor to type, have higher message throughput, and can be customized to a brand.

However, there are downsides to the short codes. To get a dedicated short code for your company can cost up to $12,000 per year. Many companies share short codes (for instance, a restaurant might have the same short code as a clothing store.). Also, cell phone carriers are getting stricter about short code spam and urging SMS marketers to switch to toll-free long codes.

Conclusion

Text-to-Give and Text-to-Donate both have pros and cons, and the decision of one over the other depends on your use case and budget.

Thanks for reading. If this was helpful, would love to hear from you! And feel free to send me any questions, comments, or corrections.

Additional Reading

How to Find and Fix a Pesky Automation — November 12, 2020

How to Find and Fix a Pesky Automation

The Business Problem

I inherited a mature Salesforce org. I am always finding new surprises – quirks and automations that make my job full of ~wonder~.

Today I ran into this issue with our online donations coming in through Formstack:

The value was supposed to be “Completed,” but an automation (process builder or workflow rule) was changing it back to “Required.” Quelle horreur!

Ah Mon Dieu, Quelle Horreur! GIF - HowDareYou - Discover & Share GIFs

How I Solved It

I created a validation rule that did not allow the status to be changed to “Required.” Here is the logic. The Follow_up__c field is the field that’s labeled “Tax Letter Status.”

AND(ISCHANGED(Follow_up__c),text(Follow_up__c)="Required")

I made the error message “cant change status” and activated the rule.

Then I filled out our donation form on our website.

It gave me this error:

From this I knew exactly which process is interfering.

I removed the node of the Process Builder process that was changing the value back to Required. I knew I could do this because it was redundant – “Required” is already the default value for this custom field on the opportunity.

Then I activated the new version of the process and deactivated my validation rule.

The result was successful:

Notes

  • It’s important to do brute force tasks like this in Sandbox so that they don’t impact the business. That said, I did this test in production because I don’t have a Sandbox version of our donation form. Do as I say, not as I do 🙂
  • It’s also important to test that everything is working just fine after you remove an automation completely (i.e. perform regression testing.)

Conclusion

Any day when an admin discovers something that’s old and obsolete is a good day. Onward!

Analyzing Data from a Multiselect Picklist – Two Options — November 11, 2020

Analyzing Data from a Multiselect Picklist – Two Options

Today I’m writing about how to use multiselect picklists in an effective way using Salesforce or Excel.

The Business Problem

We took a survey of constituents. It integrated into Salesforce and populated a multi-select picklist. Let’s say that picklist was called “Fruits” and showed a survey participant’s favorite fruits.

First mistake was using a multi-select picklist! 😉
Report of results

This report is…okay. We can see that apples are popular by eyeballing the report. But when we try to count how many people selected each fruit, we run into a bit of an issue.

This is the stuff of nightmares.

So we need another way.

Two Solutions

We can solve this issue ~for free~ in two ways:

  1. The first method involves creating formula fields in Salesforce.
    1. Benefit: The data will always be current and accurate.
    2. Drawback: If you have many options and many multi-select picklists, you can run out of fields pretty quickly.
    3. Best for when: You don’t have lots of options, you need to see aggregated data in realtime (in a dashboard or report)
  2. The second method involves Excel.
    1. Benefit: You don’t waste Salesforce fields.
    2. Drawback: You have to do some periodic copying and pasting if you want live data; can’t create dashboards easily, etc.
    3. Best when: there are lots of options, the survey period is over, you just need raw data and don’t need dashboards

Solution 1: Salesforce Fields

The idea is to create a field for each multiselect picklist option, per this help article.

I created a formula checkbox field because they are visually appealing and can be summed easily. The formula is as follows:

if(includes( Fruits__c ,"Oranges"),true,false)

The result is something like this:

We would need one field for each answer choice.

Solution 2: Excel

The second option would be to export the results and use formulas in Excel to populate columns for each answer choice.

First, I export my report results to Excel.

Then, I find all of the multiselect options. I go to the field in Setup and click Printable View. I copy this list using Cmd/Ctrl+C.

Then, I create a new tab in my Excel spreadsheet. I paste the list into that tab.

Next, I go back to the original tab and use the Transpose function in cell C1 to list out the options horizontally across the header row.

=TRANSPOSE(Options!A2:A5)

Then I used a FIND formula in cell C2 to figure out if cell B2 had the word “Apples” in it. This is probably a total kludge, so if there’s a more efficient way to do it please let me know:

=IFERROR(IF(FIND(C$1,$B2)>0,1,0),0)

This is saying that if it finds the word “Apples” in the B column at any position (position > 0), return 1. If not, return 0. I used IFERROR because it gave me an error when nothing was found. This is probably because I am an Excel noob. But hey, it works.

The $’s are there so that I can drag the formula into the other columns and it will still work – the correct row and column “sticks” and other data is dynamic. So here’s the final product:

Now we can do cool stuff like sum them up per column and even create data visualizations.

How bout them apples?

Conclusion

These solutions turn something virtually unusable into something a little less unusable. Enjoy.

PS: I’m pretty sure another option would be to feed this data into Tableau and create formulas that way. But I don’t have Tableau. If someone wants to donate a license to me for the sake of the blog, LMK.

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.