Cubic Compass - Salesforce.com Solutions
  • Home
  • Navigator
  • Services
    • Portfolio
    • Lightning Accelerator
    • CPQ Implementations
  • About
    • Contact

Migrating To Salesforce CPQ

3/11/2017

0 Comments

 
Summary

Migrating to Salesforce CPQ requires importing Orders and mapping them to many Salesforce objects (aka “Tables”) in a particular sequence. Fortunately, much of the heavy lifting can be managed using a data pipeline approach.
Migrating to Salesforce CPQ.pdf
File Size: 943 kb
File Type: pdf
Download File

CPQ Data Model Overview

There are many objects in the Salesforce CPQ data model, but only 16 objects are essential for a basic data migration. Of the 16 objects, 8 are automatically provisioned by CPQ triggers.
Picture
SalesforceCPQDataModel.png
File Size: 770 kb
File Type: png
Download File

Data Migration Pipeline

​The migration process is executed in sequential stages. Each stage must be executed and completed in it's entirety before executing the next stage. Some stages are executed by an external ETL process (Extract, Transform, Load). Other stages are executed directly in Salesforce utilizing Batch or Queueueble Apex.

During the course of configuring the data migration pipeline, adjustments may only need to be applied to a single stage, thus avoiding a complete re-import of all successive stages.

Each stage is idempotent, meaning the process can be executed multiple times without changing the result beyond the initial application. Each stage is guaranteed not to create duplicate records when re-run. This is accomplished by leveraging Salesforce's UPSERT capabilities with unique external ID fields on each object.

Concurrent processing is utilized whenever possible to reduce overall stage execution time. Some stages must be executed serially to avoid potential record locking issues.

Details for each stage are provided in the section below “Data Pipeline Stages”.
Picture
CPQ_Data_Migration_Pipeline.png
File Size: 154 kb
File Type: png
Download File

Measuring Success: Discrepancy Reporting

A “successful” CPQ migration is defined as both existing and new systems reconciling and having 0 discrepancies. If a customer is being billed $1,000 USD dollars per month today, they should continue to be invoiced $1,000 USD per month post-migration.

Discrepancy reporting typically first occurs after stage 12 in the data pipeline, when the CPQ pricing engine has an opportunity summarize all the line items to each Order. The TCV (Total Contract Value) from the originating system is compared to the TCV calculated by the CPQ pricing engine.

Common sources of discrepancies:
  • Omission of one-time charges, discounts, taxes, or shipping charges during migration.
  • Rounding errors. Decimal point resolution.
Because one-time charges have already been incurred prior to data migration, it's common practice to reconcile systems using Monthly Recurring Revenue (MRR) or Annual Recurring Revenue (ARR) metrics.

Whenever possible, discrepancies are resolved “upstream” by modifying previous stages that ultimately feed the “downstream” CPQ pricing calculation engine. Migrated orders should never be reconciled manually, as that would break the idempotent integrity of the overall process. Future executions of the migration process would overwrite any manual changes.

Discrepancy reporting is also commonly done in stage 17. Prior to sending invoices to customers, sample runs are compared to existing invoices to ensure they are consistent.

The Cubic Compass solution provides a means for automatically exporting discrepancy reports to CSV format for use in Excel reconciliation.


Case Studies

Cubic Compass has successfully implemented and evolved this migration framework since Dec 2015.
Two example case studies:

Customer A: $30M ARR Financial SaaS company.
Customer B: $100M ARR Internet Security company.

Both customers are primarily subscription-based companies with monthly and annual recurring revenue business models.

Customer A Case Study
Challenges:
  • Customer A migrated from standard Salesforce Opportunities and Quotes to Steelbrick CPQ (now Salesforce CPQ).
  • The Salesforce org contained over 10 years of customizations.
  • There were several custom triggers and non-deterministic dependencies.
  • Over 5M Lead records. Several not matched to existing Accounts.
  • Limited visibility into MRR when forecasting.
  • Order amendments required creating new Orders.
  • Hyper growth. Doubling in size every 18 months.
  • CFO needed to implement pre-IPO controls for revenue forecasting and recognition

Solution:
  • Provision new production and sandbox orgs.
  • Establish Salesforce Lightning as the default user experience.
  • Migrate legacy Opportunities to Salesforce CPQ Quotes.
  • Use of CPQ Co-Termed Contracts for Upsell Orders
  • Implement a MRR-driven subscription sales model
  • Implement Account based sales process utilizing data.com clean
  • SOX compliance controls. Accurate MRR reporting.
  • Total project time: 6-9 months

Customer B Case Study
Challenges:
  • Zuora customer. Needed to migrate from Zuora Subscriptions to Salesforce CPQ.
  • Telco usage-based-billing (UBB) not aligned with SaaS hosting model.
  • Complex pricing for multiple partner channels.
Solution:
  • Implement a Zuora connector.
  • Migrate Zuora Subscriptions to Salesforce CPQ Quotes and Orders.
  • Establish a legacy pricebook based on active subscriptions.
  • Implement CPQ pricebooks and bundles for partners.

Data Pipeline Stages
Picture
​Stage 1: Data Sources
Support for:
  • Salesforce data source
  • Zuora 360, Zuora
  • Any JDBC data source
  • Any data source with a SOAP or REST API

Stage 2: Target Salesforce Org
The migration is initially configured using a Salesforce Sandbox. Then 1-2 weeks prior to launch, the migration scripts are “replayed” to execute the same stages in a Salesforce production org.

Stage 3: Account Migration
Accounts are required for billing and are imported using the bulk API. It's common to conduct data cleansing processes in source system prior to migration. Recommend use of data.com and Salesforce Clean utilities.

Hierarchical Account migration is supported. For Salesforce-to-Salesforce migrations, the bulk migration stage automatically resolves parent Account IDs to their new record IDs.

Stage 4: Contact Migration
Billing contacts are required for invoicing. For Salesforce-to-Salesforce migrations, the bulk migration stage automatically resolves parent Account IDs to their new record IDs.

Stage 5: Pricebooks
This stage automatically creates a pricebook named “Legacy”.

Stage 6: Products
Instances of products on existing line items are imported as Salesforce Products. For migration projects that are implementing new product catalogs, this stage can optionally be extended to transform and map legacy products to new products.

Stage 7: Pricebook Entries
Migrate Products are automatically associated with Legacy and Standard pricebooks at this stage. If multi-currency is enabled, a pricebook entry is created per currency.

Stage 8: Opportunities
Active subscriptions and orders are imported to Salesforce as Closed-Won Opportunities. “In flight” open Opportunities may also be migrated.

Stage 9-10: “As Is” Quotes
These stages migrate existing subscriptions and order as Salesforce CPQ Quotes. To provision Contracts and Orders in Salesforce requires a historical reference to their corresponding Quote. These Quotes are the cornerstone for provisioning downstream CPQ objects in Salesforce.

Stage 11: “To Be” Quote
Optional transformation stage for organizations that are converting past and active orders to a new pricebook and product catalog. This is a custom batch Apex stage.

Stage 12: CPQ Pricing Engine Stage
The CPQ pricing engine summarizes all line items to produce a total amount on the Quote. Migration simply provides the raw Quantity, List Price, Term, and Discount amounts. The termed rollup is calculated by CPQ trigger processes.

Discrepancy reports and reconciliation typically starts after this stage is achieved. The Cubic Compass module for this stage has the ability to export CSV files at this stage for use in Excel.

Stage 13: Primary Quote Sync Stage
Migrated quotes are flagged as “Primary”, which synchronizes the Quote with a standard Salesforce Opportunity and Product Lines.

Stage 14: Contracts
Salesforce standard Contracts are provisioned at this stage, along with related lists of Subscription and Asset records associated with the Contract.

Contract start date, renewal date, and total amount are critical fields to evaluate post-migration.

Stage 15: Renewal Opportunities
Renewal Opportunities can optionally be provisioned at this stage, allowing for MRR/ARR custom forecasting in Salesforce.

Stage 16: Orders
Salesforce standard Orders and Line Items are 1:1 generated from CPQ Quotes at this stage.

Stage 17: Billing and Invoicing
Invoice Schedules and runs may be manually or automatically created at this stage. If credit cards will be used for processing payment, then payment gateway and payment method configuration may be required.

Stage 18: Post-Migration Tasks
Upon a successful migration, many “scaffolding” Apex classes and records may removed or inactivated. Typically a batch Apex class is maintained to conduct post-migration tasks.

0 Comments

Forecasting SaaS Revenue With Salesforce SteelBrick CPQ

4/20/2016

2 Comments

 
Picture
Software-as-a-Service (SaaS) is fundamentally a subscription business with a mix of recurring software revenue and one-time implementation services.

SteelBrick CPQ from Salesforce provides many subscription features out of the box. With some SaaS specific customizations, SteelBrick transforms Salesforce into an extremely powerful tool for forecasting and managing subscription revenue.
​
This article proposes a framework for accelerating the deployment of Salesforce + SteelBrick CPQ to address the needs of SaaS businesses.
Picture
1) Understanding SaaS Forecasting Metrics

An accelerated path to implementing SteelBrick CPQ for SaaS is to first understand and define which SaaS metrics will be used to measure and forecast revenue.

Common metrics that are rolled up at the forecasting level:

ACV / ARR: Annual Contract Value (ACV) and Annual Recurring Revenue (ARR) are often used interchangeably. Sometimes ARR is used to only represent monthly or multi-year subscriptions. ARR often requires a “customer churn” metric to reliably forecast revenue. For the purposes of this article, both ACV and ARR represent the annualized revenue from subscription services, exclusive of any one-time charges or professional services.

MRR: Monthly Recurring Revenue. ACV and ARR are commonly derived by multiplying MRR (Monthly Recurring Revenue) by 12. MRR may be a more relevant metric for businesses offering month-to-month, or cancel at anytime subscriptions.

MCV and TCV: Monthly and Total Contract Value (MCV and TCV) includes subscription revenue plus any one-time charges, such as professional services or setup and installation fees. They are useful for predicting cash flow and renewal revenue, since one-time charges are not carried forward upon subscription renewal. TCV-ACV = Service revenue is a typical calculation.
​
Once the core SaaS metrics for the business are defined, an accelerated path to implementing forecasting for SteelBrick CPQ utilizes a Salesforce feature released in Winter ’15 for predicting revenue based on custom field forecasts.
Picture
Once implemented, Executives have access to real-time forecasts of new pipeline, renewals, add-on, and service revenue.
​

2) Product Configuration

Once the core metrics are defined, the implementation starts with a “bottom-up” approach, defining the subscription and service products.
Picture
Best practices and tips:
  • Keep the product family definitions simple using just “Subscription” and “Service”. Although these are technically “revenue types”, Salesforce automatically creates forecasts based on Product Family, so this configuration accelerates implementation.
  • Create product SKUs for all subscription products and services.
  • For annualized subscription products, set the default term to 12 (months)
  • Represent free months and non-renewable discounts as separate products, and set their subscription type to “One-time” so they are not automatically added to renewal opportunities and contracts.

3) Quote Lines


SteelBrick Quotes are comprised of many Quote Lines. Each line fundamentally represents a recurring revenue subscription or a one-time service. Actual MCV and ACV values are calculated at this tier, then are rolled up by parent objects.
Best practices and tips:
  • Add custom formula fields for MRR and MCV using a combination of SteelBrick provided fields, product family, and discounts.
  • For service products, set the MRR and ARR values to $0.00.
  • Add ARR and ACV custom fields as 12x the monthly metrics.

​4) Quotes


The SteelBrick calculation engine is extremely powerful. The Quote tier is where values from the SteelBrick line item editor are merged with SaaS metrics and subscription term, then fed into the SteelBrick calculation engine to produce a detailed quote, order, or contract.
Best practices and tips:
  • Implement several Roll-up summary fields at this tier to aggregate revenue metrics.
  • Remove the SteelBrick Subscription Term field from page layout and create custom pick lists for either “Term Years” or “Term Months”, then update the underlying SteelBrick model using field update workflow formulas.
  • Implement “Free months” as a pick list on quote and modify the underlying SteelBrick subscription term model.
  • Upon Contract creation, create a workflow rule that removes any free months from renewal term.
  • Create formatted versions of formula fields for use in PDF Quote templates.
Picture

A note on approvals. SteelBrick natively implements approvals on Opportunities. But in our experience, SaaS businesses may iterate on several Quotes before finalizing an order, each one possibly requiring approval. Therefore, approvals are best implemented on Quotes.


5 & 6) Opportunity and Line Items

SteelBrick will automatically synchronize quotes with the parent Opportunity and Line Items. Opportunities are the final tier for staging revenue for forecasting, so additional formula and roll-up fields are added for more granular reporting on New vs Add-On vs Renewal revenue.

​Best practices and tips:
  • Create custom currency fields on Opportunity for the various ARR, ACV, Renewal ACV, and Add-On ACV values. Use field update workflows to keep these values in sync (forecasts do not support formula fields). Assign these fields to Opportunity splits then create custom forecast types.
  • Utilize SteelBrick’s native functionality for Contract and renewal opportunity generation.
  • Defer the creation of renewal quotes until required. Once a quote is generated on a renewal opportunity, co-termed add-on revenue will no longer appear in renewal opportunities and forecasts.
  • For calculating renewal and add-on revenue, use the previous contract value as the base target for renewal revenue. Any uplift is considered add-on (regardless of change in product quantities or seats).

​The Final Solution


Rolling up SaaS product definitions from quote lines to opportunities results in a powerful forecasting environment for managing a SaaS business on Salesforce using the subscription, calculation, contracting, quoting, and renewal capabilities of SteelBrick CPQ.

This approach is not limited to just SaaS companies. Any subscription business model; such as advertising, video, consumer “product of the month” clubs, and maintenance contracts; can reliably forecast and manage their businesses using this model.
Picture
Once revenue metrics are well defined, SteelBrick CPQ and Salesforce can be customized to support many other facets of the SaaS sales process.
Future articles:
  • SaaS Discounting Strategies: Free Months & Multi-Year Subscriptions
  • Quote to Order: Converting SaaS Quotes Into Orders
  • Compensating the SaaS Salesforce: Quotas, Splits, and Commissions.
Need assistance designing and implementing a subscription revenue solution on Salesforce?
Contact us
 to learn more.
2 Comments

Mass Updating Salesforce Profile Permissions

2/12/2016

0 Comments

 
Quick tip: Need to mass object several Salesforce profile object and field permissions?

Use the "Check All" chrome plugin (Link to plugin).

To enable only the Read checkboxes, use the following "Check All In Element" selector:
td[class*="readonlyCol"]

To enable only the Edit checkboxes:
td[class*="displayedCol"]

(Updates: via @dhoechst: there's also this plugin more specifically suited to the task.
April '16: Updated regex syntax for matching columns to reflect recent changes in Summer '16)

Picture
0 Comments

In-Person Mobile eSignatures With Salesforce1

11/5/2015

1 Comment

 
Closing deals doesn't get any faster when eSignatures are captured in-person using Salesforce1.

With the Salesforce1 mobile application, Salespeople configure orders and hand the smartphone over to the customer for immediate review and eSignature.
​
Custom mobile application developed using the Cubic Compass Lightning Accelerator.
Picture
Picture
eSigned documents are attached to Salesforce records and emailed as a attachments to the customer. Lightning process builder kicks-off any order fulfillment workflow processes.

Signed and done... all using the power of Salesforce1 Mobile!
Picture
Picture
1 Comment

Developing Lightning Applications With ReactJS

10/23/2015

0 Comments

 
Won't you listen 'cos I'm at it again
Lightning striking, and on that you can depend
They say that lightning never strikes the same place twice
Gods of thunder, sit and watch the event
-Ozzy Osbourne Lightning Strikes
The Salesforce Lightning Design System provides a library of pre-built UI elements.

"Thinking in React" is essentially the art of breaking down larger user interfaces into several smaller components.

Combined, the two provide an extremely powerful framework for building interactive user interfaces in Salesforce.
Picture
Lightning Tabs

Let's use the Lightning Tabs component as an example. After pasting the example code into a Visualforce page, a very nicely formatted navigation menu will appear in the page.
Picture
However, without Javascript, clicking on the tabs will have no effect.

To make this navigation tab interactive, we'll wrap the individual Tab components in React classes. We begin by deconstructing the Tab UI down into smaller classes that can be implemented in React.

A hierarchy of React components representing a Lightning tab navigation:
App   (The application container)
   Tabs   (A collection of tabs)
      Tab     (A single tab instance)
         Content    (Content associated with a tab)


Data

ReactJS components "react" to changes in data state. The data we're going to inject into this application is an array of Tabs, defined as follows:
    var tabList = [
      { 'index': 0, 'title': 'Item One', 'content':
        <div id="tab-scoped-0" class="slds-tabs__content slds-show" role="tabpanel">
            <h2>Item One Content</h2>
        </div>
      },
      { 'index': 1, 'title': 'Item Two', 'content':
        <div id="tab-scoped-1" class="slds-tabs__content slds-show" role="tabpanel">
            <h2>Item Two Content</h2>
        </div>
            },
      { 'index': 2, 'title': 'Item Three', 'content':
        <div id="tab-scoped-2" class="slds-tabs__content slds-show" role="tabpanel">
            <h2>Item Three Content</h2>
        </div>
      }
    ];



App

Now this is where the ReactJS framework comes into play. The App class provides the outermost container for the entire application. The state of which tab is currently selected is managed in the App class.
      
    var App = React.createClass({
      getInitialState: function () {        
        return {
          tabList: tabList,
          currentTab: 0
        };
      },
            
      changeTab: function(tab) {
        this.setState({ currentTab: tab.index });
      },
            
      render: function(){
        return(
          <div className="slds">
            <Tabs 
              currentTab={this.state.currentTab}
              tabList={this.state.tabList}
              changeTab={this.changeTab}
            />
                  {this.state.tabList[this.state.currentTab].content}
          </div>
        )
      }
    });

Tabs

The App.render() method constructs a Tabs class, which is a container for many individual tabs.
    var Tabs = React.createClass({
      handleClick: function(tab){
                this.props.changeTab(tab);
      },
            
      render: function(){
        return (
          <div className="slds-tabs--scoped">
          <ul className="slds-tabs--scoped__nav" role="tablist">
          {this.props.tabList.map(function(tab) {
            return (
              <Tab
                handleClick={this.handleClick.bind(this, tab)} 
                index={tab.index} 
                title={tab.title} 
                isCurrent={(this.props.currentTab === tab.index)}
              />
            );
          }.bind(this))}
          </ul>
          </div>
        );
      }
    });

Tab

The majority of dynamic rendering occurs in the Tab class.
      
    var Tab = React.createClass({
      handleClick: function(e){
        this.props.handleClick();
      },
            
      render: function(){
        var tabClass = "slds-tabs__item slds-text-heading--label";
        tabClass += (this.props.isCurrent ? ' slds-active' : '');
                var selected = (this.props.isCurrent ? 'true' : 'false');
                var path = '#' + encodeURIComponent( this.props.title.toLowerCase() );
                var controls = 'tab-scoped-' + this.props.index;
        return (
          <li className={tabClass} title={this.props.title} role="presentation"><a href={path} onClick={this.handleClick} role="tab" tabindex={this.props.index} aria-selected={selected} aria-controls={controls}>{this.props.title}</a></li>
        )
      }
    });

Finally, this snippet of code sets the whole interactive model in motion. It creates an instance of the <App/> class within the document <body> tag.
    
    React.render(
      <App />,
      document.body
    );

Event Handling

You'll notice that the Tab onClick event gets bubbled up through the Tabs container, and is ultimately handled by the App class.

Events are handled at the most appropriate scope in an application. In this case, the App class updates the currentTab variable and the entire DOM is automatically updated to reflect the change in state.

Also notice that no dynamic removeClass() or addClass() logic is required to re-render the tabs. This is where the real magic of React is utilized.

​React manages a virtual DOM (Document Object Model) and diff engine to automatically determine which components in the hierarchy need to be re-rendered every time there is a change in data state.

​The Whole Enchilada

Wrapping Lightning Design Studio components in React classes is a remarkably powerful and efficient combination.

An interactive navigation menu can be implemented in under 100 lines of code without writing any custom CSS or complex JS event handlers. Entire source code for this example is below.
Need a custom Salesforce application or AppExchange product developed using the latest Lightning design studio components? Contact us for details.
<apex:page showHeader="false" standardStylesheets="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false" docType="html-5.0" cache="false">
<html xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <head>
  <title>App Title</title>
  <apex:stylesheet value="{!URLFOR($Resource.SLDS092, 'assets/styles/salesforce-lightning-design-system-vf.css')}" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react-dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  <script type="text/babel">
    var tabList = [
      { 'index': 0, 'title': 'Item One', 'content':
        <div id="tab-scoped-0" class="slds-tabs__content slds-show" role="tabpanel">
            <h2>Item One Content</h2>
        </div>
      },
      { 'index': 1, 'title': 'Item Two', 'content':
        <div id="tab-scoped-1" class="slds-tabs__content slds-show" role="tabpanel">
            <h2>Item Two Content</h2>
        </div>
            },
      { 'index': 2, 'title': 'Item Three', 'content':
        <div id="tab-scoped-2" class="slds-tabs__content slds-show" role="tabpanel">
            <h2>Item Three Content</h2>
        </div>
      }
    ];
      
    var App = React.createClass({
      getInitialState: function () {        
        return {
          tabList: tabList,
          currentTab: 0
        };
      },
            
      changeTab: function(tab) {
        this.setState({ currentTab: tab.index });
      },
            
      render: function(){
        return(
          <div className="slds">
            <Tabs 
              currentTab={this.state.currentTab}
              tabList={this.state.tabList}
              changeTab={this.changeTab}
            />
                  {this.state.tabList[this.state.currentTab].content}
          </div>
        )
      }
    });
      
    var Tabs = React.createClass({
      handleClick: function(tab){
                this.props.changeTab(tab);
      },
            
      render: function(){
        return (
          <div className="slds-tabs--scoped">
          <ul className="slds-tabs--scoped__nav" role="tablist">
          {this.props.tabList.map(function(tab) {
            return (
              <Tab
                handleClick={this.handleClick.bind(this, tab)} 
                index={tab.index} 
                title={tab.title} 
                isCurrent={(this.props.currentTab === tab.index)}
              />
            );
          }.bind(this))}
          </ul>
          </div>
        );
      }
    });
      
    var Tab = React.createClass({
      handleClick: function(e){
        this.props.handleClick();
      },
            
      render: function(){
        var tabClass = "slds-tabs__item slds-text-heading--label";
        tabClass += (this.props.isCurrent ? ' slds-active' : '');
                var selected = (this.props.isCurrent ? 'true' : 'false');
                var path = '#' + encodeURIComponent( this.props.title.toLowerCase() );
                var controls = 'tab-scoped-' + this.props.index;
        return (
          <li className={tabClass} title={this.props.title} role="presentation"><a href={path} onClick={this.handleClick} role="tab" tabindex={this.props.index} aria-selected={selected} aria-controls={controls}>{this.props.title}</a></li>
        )
      }
    });
    
    React.render(
      <App />,
      document.body
    );
    </script>
  </head>
  <body></body>
</html>
</apex:page>
0 Comments

    Author

    Mike Leach is Founder and Principal Consultant at Cubic Compass; a software design and development consultancy focused on the Salesforce Force.com platform.

    Archives

    March 2017
    April 2016
    February 2016
    November 2015
    October 2015

    Categories

    All

    RSS Feed

Cubic Compass     |     PO Box 2582 El Cerrito, CA 94530 
info@cubiccompass.com
  • Home
  • Navigator
  • Services
    • Portfolio
    • Lightning Accelerator
    • CPQ Implementations
  • About
    • Contact