How-to: Advance Revenue Recognition in NPSP Accounting Subledger (ASL)

August 11, 2020 by Eddie Blazer

“Revenue is not cash and cash is not revenue.” This concept blew my mind when I was first introduced to accounting and it’s one of the things that can make accounting feel like a dark art, especially for non-profits managing several restricted funds. Enter’s new Accounting Subledger (ASL) product.

Disclaimer: I’m not an accountant, I only pretend to be one for my own company ;).

We recently had the opportunity to set up ASL for a museum client who migrated to Salesforce from Tessitura. During this project, we learned that ASL can use Salesforce Opportunities, GAU Allocations (synonymous with “Campaigns”, “funds”, and “designations” on other platforms like Raiser’s Edge and Tessitura), and Payments to automatically create the debits and credits for pledges and payments, but isn’t quite as easy when it comes to revenue recognition.

For example, let’s say Donor X pledges to donate $100,000 to your organization’s museum upgrade project (presently not started). In NPSP, the gift officer would create a pledge opportunity with a single GAU Allocation referencing the Museum Upgrade Project GAU. This results in the following Ledger Entry records (which can be imported to the accounting system as journals):

Debit $100,000 Receivables 
 Credit $100,000 Museum Upgrade Project

In the journal above, ASL has assumed the monies are revenue and assigns the credit to the revenue account called “Museum Upgrade Project”, matching the name of the GAU. However, this project hasn’t started yet and therefore the monies should be deferred. Thus our challenges have presented:

  1. The initial credit should be to a deferred revenue account
  2. Later, the system should generate subsequent entries “earning” the revenue

After speaking with the product manager and doing some of our own research we discovered we had a few options.

Transfer revenue across GAUs

This is ASL’s out-of-the-box approach to revenue recognition. In NPSP+ASL, GAUs are roughly synonymous with revenue accounts in your accounting system. So with this approach, the organization creates a GAU for Deferred revenue (or creates 1 deferred GAU for each restricted GAU), and donations are allocated entirely to the deferred GAU. Monies are later re-allocated to the “real” GAU when it’s time to recognize the revenue. ASL will see these transfers and create ledger entries that debit the Deferred Revenue GAU, and credit the “real” GAU.

However, in practice this isn’t easy. First, I need to give some technical background on ASL. ASL introduces a new concept: Payment Allocations.

Where Opportunity Allocations are the junction between Opportunities and GAUs, Payment Allocations are the junction between Payments and Allocations. They effectively tell the system, “Part of this payment goes to this GAU and the other part goes to this GAU”. This is necessary when a donor calls and says “Here’s that $50,000 check, but instead of being split 50/50 like we talked about, I want this check to be split 75/25.”. What’s important about this is that Payment Allocations are not a new object in the system; Salesforce overloaded the existing Allocation object, making it do double duty.

Manage Allocations Error

So, why isn’t it easy? Well, if the opportunity has any payments marked as Paid, the Opportunity Allocations cannot be modified (NPSP throws the error above). Instead the user must perform the revenue transfer via “Payment Allocations”. Fortunately, Payment Allocations have a “manage allocations” button, which uses the same familiar interface as with Opportunity Allocations. But if you have an opportunity with multiple GAUs and multiple payments, there is a lot more clicking as you need to navigate to each opportunity and each of its payments to manage those allocations and transfer the revenue. Doing this at scale (common for capital campaigns, etc) will take significant time. Lastly, as Payment Allocations are adjusted, Opportunity Allocations are automatically updated to reflect reality (going the other direction would be nice!).

Something to be aware of is that reporting on Allocations is not as simple as before and now need to be aware that the Allocation object is now overloaded and needs to be filtered to either show Opportunity Allocations or Payment Allocations; reporting on both will result in weird numbers.

Because of the extra steps needed to manually transfer between GAUs, we investigated automation via a batch Apex job and some kind of object that would define the earn schedule (either on an opportunity-by-opportunity basis, or on a master schedule defined at the GAU level). While this is possible, it was beyond our client’s budget, and seems like something Salesforce may eventually support.

Manual Revenue Recognition

This one’s exactly what it sounds like. The Accounting department would manually record journal entries in their accounting system to recognize revenue as appropriate. Aside from the obvious labor-time impact, it has the other downside that transactions are no longer traceable to their source, increasing risk of error and audit time.

However, for organizations already used to managing revenue recognition this way, it’s not an invalid approach.

To make this easier, a custom object can be used to track the revenue schedules for any particular GAU. A simple report on these records could quickly help Accounting identify when and how much they should be recognizing manually within their accounting system.

Instead of a custom object we briefly considered leveraging Opportunity Product Revenue Schedules (which have the added benefit of not consuming any data), but that requires each allocation to have a companion Opportunity Product, which opens pandoras box around keeping the two records in sync. Additionally, once an Opportunity Product has revenue schedules, the Opportunity Product’s price fields can no longer be modified directly.

Wait for Native Support

As mentioned earlier, this need feels like a capability that Salesforce will likely add to the product at some point. Afterall, this is one of the core values of cloud-based subscriptions. So while the upside is less effort, less money, and less technical debt, the obvious downside is not knowing if or when it’ll come.

#safeharbor: make your purchasing decisions on current features!

Hack ASL

It’s so tempting and seems so easy. A time-based workflow rule or process builder, or batch apex job could create the proper debits and credits easily enough, right? Well, as it turns out ASL does not let users create Ledger Entry records via the UI, API, Apex, or Workflow/PB/Flow. This makes sense; Salesforce put some safeguards in place to maintain the integrity of data that’s going to be fed into an accounting system.

But… to be honest, I had a bit of an itch to scratch here. I wanted to provide our client with perfect NPSP+Accounting nirvana. After all, Foglight has built custom accounting solutions for others, and we felt confident we could tackle this problem. So we decided to investigate further, and after a little digging, discovered a back door that allowed us to create our own Ledger Entries.

However, this approach comes at great cost and risk; designing, building, and testing this kind of solution would take time and money, and comes with the risk of becoming throwaway should Salesforce ever decide to release their own capabilities here (adding additional costs for migration). Additionally, it ran the risk of being brittle; Salesforce could close the back door at any time without warning.

But it can be done (How? Call us.)


After thinking through the options, we recommended to our client that they perform revenue recognition manually in their accounting system while waiting for Salesforce to address this need directly. This approach was ok for them since they were already performing revenue recognition manually and because 90% of their recognition was on the same schedule, and ultimately, this work is relatively little effort compared to the rest of what ASL is doing for them. We solved 80% of their need with far less than 20% effort. Pareto be like, wow.

However, this solution won’t work for all clients. Organizations that receive purpose-restricted funds, or have time restrictions that are variable across donations, or have a high volume of recognition transactions may want to pursue other options where Salesforce can perform this revenue recognition more gracefully.

So, How?

Here, I’ll walk you through the steps to execute on the first option above: transferring revenue across GAUs. I assume you’ve already installed and configured Accounting Subledger.

First, create a “Deferred Revenue” GAU and a “2021 Museum Upgrade” GAU.

Create a $100,000 opportunity, setting “Do Not Automatically Create Payment” as checked (we want to schedule those later) and Stage as pledged.

Manage Allocations Error

Next, click “Manage Allocations” on the Allocations related list, and select the “Deferred Revenue” GAU.

Manage Allocations Error

Navigate to the Payments related list and click “schedule payments”, create a schedule of 5 payments over the next 5 years. Mark the first as paid, leave the others as unpaid.

Manage Allocations Error

Now, click on the first payment. Observe the Payment Allocations related list (add it if it’s not there), and that it points to deferred GAU.

Manage Allocations Error

If your ASL is setup for batch mode and has triggers turned off, run the “Accounting Scheduled Job” (on the “Accounting Settings” tab) to generate the ledger entries.

Manage Allocations Error

Back at the Opportunity, you should now see Ledger Entries on the oppy.

Manage Allocations Error

Now, let’s pretend that it’s time to recognize 30% of that revenue. Remember, cash is not revenue so it doesn’t matter if all of the payments are “paid” or not. Navigate to the detail page for the first Payment, then click “Manage Allocations” on the “Payment Allocations” related list.

Manage Allocations Error

Change the allocations as follows:

Manage Allocations Error

Click Save. Repeat the step above for each Payment on the opportunity.

If you did it correctly, the Opportunity’s Allocation’s should now be automatically updated and look like:

Manage Allocations Error

Lastly, run the “Accounting Scheduled Job” one last time to generate Ledgers that debit the Deferred and credit the earned revenue account. If you look at the opportunity’s Ledger Entries, you should see significant changes.

Manage Allocations Error

The short story here is that ASL is reversing all of the transactions to a $0 balance, then creating new transactions to represent the 30% earn. While this technically works, it’s not as elegant as a single debit from deferred and credit to the earn account.

Manage Allocations Error

Ok, so we’ve just recognized 30% of the revenue for the Museum Upgrade Project across one opportunity. You can see that this is a pretty involved process that needs to be executed for each payment within each opportunity, which doesn’t scale well at all. The good news is that this can be automated with some Batch Apex magic. (How? Call Us.)


Managing allocations manually isn’t a very scalable way to perform revenue recognition, but it is currently ASL’s only out-of-the-box option. And while the Ledger Entries aren’t quite as elegant as we’d like them, they do technically balance. This approach can be automated to make the user experience better and save even more time, but for some organizations it may be better to wait for Salesforce to address this natively.

If your organization is considering Salesforce Accounting Subledger, needs help with revenue recognition, or want to pursue some of the options above, click the contact button below to learn how we can help you.

Eddie Blazer


Eddie Blazer | Partner

Eddie Blazer is founder and President of Foglight Solutions. He’s passionate about delivering high value business solutions to help clients develop deeper connections with their customers.