We use cookies that are able to read, store, and write information to the browser on your device. This data may contain personal identifiers. You can opt in to all cookies, decline non-essential cookies, or manage your options.

These cookies are used to improve our site performance. Some cookies are necessary for our website and services operation. Other cookies help personalise your experience and are optional, such as advertising and analytics. You can opt in to all cookies, decline non-essential cookies, or manage your options.

How to Build a Automated Dealer Sign Up Paywall for Onboarding New Dealers as Members

Use the standard StoreConnect checkout for a minimal dealer paywall application process, to get your dealers buying stock straight away.

June 18, 2024

This tutorial is a continuation of the topic and a solution variation from our article: How to Build an Application Form with Payment on Salesforce

Which will showcase a different solution for a similar business process but one that focuses on a Business-to-Business (B2B) scenario and where we explore some different solutions.

A scenario where product prices are not displayed to public viewers and where you want sales facilitated through a network of dealers.
Example Image of site that has products without prices or the ability to order without being a dealer

Imagine a vendor of a range of fitness equipment products who is experiencing a large influx of unqualified dealer sign-ups. Some high-value leads are being handled by these unqualified dealers, when they should be purchasing through authorised dealers. The vendor wants higher quality commercial dealers and a smaller overall number of dealers during a growing product awareness phase of the business. By setting up a Dealer Pricebook, we can offer specialised pricing to gyms and fitness centers that purchase these products, sometimes in bulk.

This article is going to outline a fully automated process for a B2B product vendor to onboard new dealers and have them ordering dealer pricing products in minutes via an application fee or paywall. Where this can also be circumvented for edge cases with a code, for people-managed dealer sign-ups.
Example Image of Product with an Apply now button

Keep in mind; you may implement manual touchpoints for your own human interactions for your specific dealer onboarding journey. You can modify this solution to your needs. For example, using a Web-to-Lead Content Block in place of the Application Fee product used here.

For a video of this tutorial see here:

As a StoreConnect Salesforce admin, we will be touching these key elements to set up this functionality. We will learn to implement:

  • Product Configuration.
  • Store Configuration.
  • Price Book Configuration.
  • Price Book Entry Configuration.
  • Simple Conditional Liquid in a Store Head Block.
  • Some StoreConnect Theme Template code for a Product Card.
  • Membership Configuration.
  • Promotion Configuration.

Image of solution diagram

Once these configurations are in place, we will have a live fully automated dealer sign-up process using simple StoreConnect functionality.

1. Install StoreConnect

To host this on a website, we need to get StoreConnect installed, so let’s get that started.

Before beginning with StoreConnect, ensure it is installed and properly set up.

For this tutorial, we will use and build upon the StoreConnect Trial which has some products and stores set up and in place for us.

You can install a StoreConnect trial to follow this guide if you are not working on a production or sandbox site implementation.

If you wish to implement in your own Salesforce Org, here is the installation guide.

Check that your StoreConnect Store and Site are active with a functional URL.

Step 1 Option 1

Once this is complete, you should have a StoreConnect Store and Site that is accessible online.

Step 1 Result 1

If you are installing StoreConnect as a package into your production or sandbox org, check to see this entry in the Installed Packages setup screen:

Step 1 Result 2

2. Designing a Dealer Membership and Pricing Framework

Our StoreConnect Trial has a multi-tiered price books and pricing for products in place as part of the demo. We will automate the following process to add a new dealer to the first level dealer pricing as the Professional Tier.

Results:

The price books are:
1. Standard Price Book.
2. Hidden.
3. Professional Tier.
4. Corporate Tier (Next Tier - Optional).

Image of Product Record with Price book entries

2.1. If you are not using the StoreConnect Trial and do not have a tiered price book setup for your products. Let’s look at how you might establish a dealer pricing model. Consider these Pricebooks:

  1. Standard Price Book: Recommended retail price (RRP).
  2. Hidden Price Book: Functions to hide pricing.
  3. Dealer Price Book: We will calculate to 80% of the retail price.
    (Further Tier Dealer Pricebooks: Many price books can be created for different accounts, individuals, stores, or groupings of accounts.)

Assume we’ve added 2 new products. Let’s update all the new products across the store to have a price book entry. We’ll update in bulk using a data load. Use your data loader option of choice. I personally use dataloader.io

Firstly let’s export the Product Records from Product2. Just the ID and Name field will be required for this. Filter your export as desired.

Here is an example of the export with 2 rows, assuming this is the scope of our products (you may be dealing with 100’s or 1000’s of products):

Product ID Product Name
01tQE000001sGIUYA2 ACME Widget Master 2000
01tQE000001sGIUYA3 ACME Widget Device 1000

Now we have the Product Id’s and know the name of the products. Let’s add some columns for the Standard Price Book Entry and its retail price. Find the Salesforce Id of your Standard Price Book and copy that to each cell in the Standard Pricebook ID column. Give your Products an RRP List Price and Set the Active cells to TRUE

Product ID Product Name Standard Pricebook ID List Price (RRP) Active
01tQE000001sGIUYA2 ACME Widget Master 2000 01sQE0000009sijYAA 500.00 TRUE
01tQE000001sGIUYA3 ACME Widget Device 1000 01sQE0000009sijYAA 249.99 TRUE

Let’s insert these records creating new Price Book Entry Records.
Great! Let’s now set the Hidden Price Book Entries for all products.

Product ID Product Name Hidden Pricebook ID List Price Active Hide Price
01tQE000001sGIUYA2 ACME Widget Master 2000 01sQE0000009sijYAA 500.00 TRUE TRUE
01tQE000001sGIUYA3 ACME Widget Device 1000 01sQE0000009sijYAA 249.99 TRUE TRUE

Let’s insert these records creating new Price Book Entry Records.
Excellent! Let’s now set the Dealer Price Book Entries for all products.
We can use a spreadsheet formula like =D2*0.8 in the Sales Price cell rather than working out each price individually if we like.

Product ID Product Name Dealer Pricebook ID List Price Active Sale Price
01tQE000001sGIUYA2 ACME Widget Master 2000 01sQE0000009sijYAA 500.00 TRUE 400.00
01tQE000001sGIUYA3 ACME Widget Device 1000 01sQE0000009sijYAA 249.99 TRUE 199.99

Let’s insert these records creating new Price Book Entry Records.

Note here that for the dealer pricing we are using the Sales Price Field while keeping the RRP in the List Price. This is to show the dealer the margin via displaying the sale price in red with the RRP crossed out on the product. You may wish to not use this method for dealers and simply set the List Price as the New Dealer Price and only use the Sale Price for products “On Sale”

Results:

All our products that we would like to display on our vendor site, have a hidden public price, a retail Standard Price, and a Dealer price.

3. Configuring Hidden Price Products

For products where prices are not publicly displayed, we set up a Hidden Price Pricebook for our products. The store is then set to this Pricebook to facilitate this B2B approach. This maintains the exclusivity of pricing information, accessible only to approved dealers that require a login.

We will implement this in the StoreConnect Trial org on the Sports Store as it has the following - Products that meet the visible requirements for a store. - A pricebook entry with the Hide Price flag checked across all the products.

Let’s configure the StoreConnect Trial to model a B2B site where you must login to see prices and order products.

  1. Navigate to the StoreConnect Config application.
  2. Select the ‘Sports Store’ record.
  3. Scroll down to the PriceBook field and change the ‘Standard Price Book’ to ‘Hidden’ using the field search dialogue box.
  4. Uncheck ‘Product Price is Tax Inclusive’ checkbox as this is a B2B store use case where Tax is not inclusive.
  5. Click Save.
  6. Click the Hidden pricebook hyperlink and edit this record: rename the Hide Price Text to ‘Apply for Prices’ and rename the Unavailable Text field to ‘Available via our Dealers’.

Results:

Hidden Pricebook Record

3.1. If you are not using the StoreConnect Trial check these pre-requisites:

This section will be dot points and references, rather than steps, to highlight the requirements to get us to the same point as the trial demo products.

Create New Pricebooks:

  • Create a New Pricebook called ‘Hidden’, check Active is ‘true’, rename the Hide Price Text to ‘Apply for Prices’ and rename the Unavailable Text field to ‘Available via our Dealers’.
  • Create a New Pricebook called ‘Dealer Pricing’ and check Active is ‘true’.

Configure Store Record

  • In the Store Object List, ensure you have a store record with a live url.
  • In the PriceBook field and change the ‘Standard Price Book’ to ‘Hidden’.
  • Uncheck ‘Product Price is Tax Inclusive’ checkbox as this is a B2B store use case where Tax is not inclusive.
  • Ensure your store has a Taxonomy. If one does not exist for your store create one now.
  • Ensure a store payment provider is configured. If not configure a ‘Pay Later’ option is set up for simplicity.
  • Ensure there is a Product Category for your store that is associated with the Taxonomy of your live store.

Configure Product and Price Book Entry Records:

  • Ensure there are some products visible and purchasable on the store and they have at least three price book entries:
  • For the ‘Standard Product Pricebook’ with an intended retail price.
  • For ‘Hidden’ Pricebook with 1 for price, then click save and apply to all.
  • For Dealer Pricing Pricebook with a discounted dealer price from the standard price, then click save and apply to all.
  • Upload and associate Media to these products if desired.

Results:

In the StoreConnect Salesforce Configuration:

  • We should have configured Store, Taxonomy, and Product Category record.
  • We should have a ‘Standard Price Book’, ‘Hidden’ and ‘Dealer Pricing’ price book records configured.
  • Our store record should be set to the Hidden price book.
  • We should have one or more Product records linked to the three above price books, a product category, and visible on the store.

Image of Store Record Setting

On our live store:

  • We should have a live store where we can navigate to one or more products visible on a product category listing page of a live store.
  • We should see our products listed on the product category page without prices and the values we set for Buy it Now button.
  • We should see the product detail page that does not show the price or allow the product to be purchased. Specifically, when we are not logged into the store. Example Image of site that has products without prices or the ability to order without being a dealer

4. Setting Up a ‘New Dealer Application Fee’ Product

For the dealer application process, we will use the standard data capture fields from the StoreConnect checkout flow. We will need to create an ‘Apply Now’ product. This product will be associated with a nominal application fee, serving as the initial step and paywall for businesses wishing to become dealers. The commercial intent being to filter serious applicants but also automate the entire onboarding process in a super simple out-of-the-box StoreConnect functionality. Let’s also create a Promo Code to cancel the fee for special dealer onboarding processes where partner managers can remove the paywall.

  1. Create a new Product.
  2. Product Name ‘New Dealer Application Fee’.
  3. Active = True, Is Master = True, Is Virtual = False, Track Inventory = False.
  4. Available On = A Date/Time in the past.
  5. Click Save.
  6. Create a New Product Category called ‘Administration’ click Save.
  7. Associate the New Dealer Application Fee product with the Administration product category and click Save.
  8. Navigate to the New Dealer Application Fee product and Add a Standard Price Book entry of = $49.99 or whatever price you desire and click Save.
  9. Add a Hidden price book entry of = $49.99 or whatever matches your fee. Ensure that you uncheck the Hide Price checkbox, check the “Disable Quantity Selection” checkbox and set ‘Order Quantity Maximum’ to 1. Set ‘Add to Cart Text’ to Add Application to Cart and ‘Buy it Now Text’ to Apply Now.
  10. Click Save.

Results:

We should see the New Dealer Application Fee product and when we are not logged into the store, we should see a price and have the ability to checkout and pay/purchase the application. Image of Product Record SC Results

Image of Product on the site

Note: Try not to fully complete the checkout yet as we will do this later to create a dealer login account as part of the complete solutions final checkout step process.

5. Crafting a Content Block for the Application Component

Let’s create a content block, specifically for hidden price products, that shows up on the public facing vendor product. This content block serves as a clear call-to-action, we will use a liquid template so that it can be further customised in detail if required.

  1. Navigate to the StoreConnect CMS application
  2. Create a new Content Block record called “New Dealer Application Fee Block”
  3. Select “No Added Styling” as the Type dropdown
  4. We will use some markup code from the liquid code of the Product Card template snippet snippets/products/card and modify it to display a customised and unique version of our New Dealer Application Fee product.
  5. The modifications we are making are:
    Assigning a specific product by adding the line (3rd line) assign product = all_products['product-slug'] ensure that you change product-slug to the Product Slug field of the ‘New Dealer Application Fee’ product record we made in the previous step.
    Removing the href=" product.path " from line 7 only to remove the on-click navigation to the product on the image.
  6. Insert the modified code:
Hidden Price Product Content Block
liquid

{%- default product: blank -%}
{%- default show_compare: false -%}
<span style="color:red">{% assign product = all_products['product-slug'] %}</span>
{%- cache "product", items: [product, current_store, current_customer, show_compare] -%}
<div class="SC-ProductCard" id="product_{{ product.id }}">
  {%- comment %} Image{%- endcomment %}
  <span style="color:red"
    ><a class="SC-ProductCard_image">
      {%- if product.image != blank %}
        <img loading="lazy" src="{{ product.image.medium_url }}">
      {%- else %}
        {% render 'shared/placeholder_image' %}
      {%- endif %}
    </a>
  </span>
  {%- comment %} Tags{%- endcomment %}
  {%- if product.tags.size > 0 %}
    <div class="SC-ProductCard_tags">
      {%- assign tags = product.tags %}
      {% for tag in tags %}
        <span class="SC-ProductCard_tag SC-ProductCard_tag-{{ tag.value | parameterize }}">
          {{ tag.value }}
        </span>
      {% endfor %}
    </div>
  {%- endif %}
  {%- comment %} Headline{%- endcomment %}
  <a class="SC-ProductCard_headline" href="{{ product.path }}">{{ product.name | truncate: 70 }}</a>
  {%- comment %} Detail{%- endcomment %}
  <div class="SC-ProductCard_subheadline">
    {%- comment %} Price{%- endcomment %}
    <div class="SC-ProductCard_price">
      {%- if product.pricing.hide_price? %}
        <span class="SC-ProductCard_price_item">
          {{ product.pricing.hide_price_text }}
        </span>
      {%- elsif product.restricted? and product.restricted_text != blank %}
        <span class="SC-ProductCard_price_item">
          {{ product.restricted_text }}
        </span>
      {%- elsif product.pricing.has_price? %}
        {%- if product.pricing.on_sale? %}
          <span class="SC-ProductCard_price_item is-sale">
            {%- if product.pricing.sale_price == 0 %}
              {{ 'pricing.free' | t }}
            {%- else %}
              {%- capture price %}{{ product.pricing.sale_price | money }}{%- endcapture %}
              {% if product.pricing.variable_pricing? %}
                {{ 'pricing.variable' | t: price: price }}
              {%- else %}
                {{ price }}
              {% endif %}
            {%- endif %}
          </span>
          <span class="SC-ProductCard_price_item is-original">
            {{ product.pricing.original_price | money }}
          </span>
        {%- else %}
          <span class="SC-ProductCard_price_item">
            {%- if product.pricing.price == 0 %}
              {{ 'pricing.free' | t }}
            {%- else %}
              {%- capture price %}{{ product.pricing.price | money }}{%- endcapture %}
              {% if product.pricing.variable_pricing? %}
                {{ 'pricing.variable' | t: price: price }}
              {%- else %}
                {{ price }}
              {% endif %}
            {%- endif %}
          </span>
        {%- endif %}
      {%- endif %}
      {%- comment %} Subscriptions{%- endcomment %}
      {%- if product.subscription? %}
        {%- capture timespan %}
               {%- liquid
                  assign term = product.pricing.subscription_term | number, compact: true
                  assign unit = product.pricing.subscription_term_unit
                  if term != blank and unit != blank
                    render "shared/subscriptions/term_unit", unit: unit, number: term
                  endif
                %}
             {%- endcapture %}
        <span class="SC-ProductCard_subscription">
          {{ 'pricing.subscription_timespan' | t: timespan: timespan }}
        </span>
      {%- endif %}
    </div>
    {%- comment %} Restrictions{%- endcomment %}
    {%- if product.restricted? %}
      <div class="SC-ProductCard_restricted sc-mb-small">
        {% render 'products/restricted', product: product, compact: true %}
      </div>
    {%- endif %}
    {%- comment %} Fulfilment{%- endcomment %}
    {%- unless product.restricted? and product.current_approved_quantity <= 0 %}
      <div class="SC-ProductCard_fulfilment">
        {%- if product.can_purchase? %}
          {%- if product.can_pickup? %}
            {%- if product.can_ship? %}
              {{ 'products.pickup.available' | t }}
            {%- else %}
              {{ 'products.pickup.only' | t }}
            {%- endif %}
          {%- endif %}
        {%- else %}
          {%- if product.bookable? %}
            {{ 'products.availability.sold_out' | t }}
          {%- elsif product.track_inventory? %}
            {{ product.out_of_stock_text }}
          {%- else %}
            {{ product.unavailable_text }}
          {%- endif %}
        {%- endif %}
      </div>
    {%- endunless %}
  </div>
  {%- comment %} Actions{%- endcomment %}
  <div class="SC-ProductCard_actions">
    {% if product.can_purchase? and product.current_approved_quantity > 0 %}
      {%- comment %} Buy now{%- endcomment %}
      {%- unless theme_variables['products.card.hide_purchase_button'] == true %}
        {%- render 'products/card/buttons', product: product %}
      {%- endunless %}
    {% endif %}
    {%- comment %} Compare{%- endcomment %}
    {%- if show_compare %}
      <div class="sc-me-tiny">
        <label class="SC-Checkbox">
          <input data-js-compare-add id="{{ product.id }}" class="SC-Checkbox_input" type="checkbox">
          <div class="SC-Checkbox_label">
            {{ 'products.compare.add_to_compare' | t }}
          </div>
        </label>
      </div>
    {%- endif %}
  </div>
</div>
{%- endcache -%}

Results:

We should have a product card Content Block with an identifier. Image of Content Block record and identifier field

5. Leveraging Conditional Liquid Logic

Incorporating conditional liquid logic into your site’s head block allows for the ‘New Dealer Application Fee’ product card to display based on product-specific pages that have a hidden price. This will show the ‘New Dealer Application Fee’ - ‘Apply Now’ option only for products that fit the criteria.

What is Liquid?:

Liquify is a made-up verb to describe us rewriting how our app produces the HTML that the browser renders into pretty online stores. Initially, StoreConnect was a simple web app - we did the coding plus the layout & design of the web app. And then each client, one by one, says, “But we want our site to look different.” So, we needed to switch how we make all this work. We need a way to make StoreConnect “just work” with a vanilla theme for everyone and allow each client to incrementally re-theme parts of the store. First, they’ll theme the home page, then the product pages, then search pages; We’re working on converting our app so clients can retheme the various pages we display during checkout and payment. But why is it called liquifying? A made-up verb? Our clients can now overwrite our default themes — thus retheming their stores — using a library/tool/thing called Liquid Templates. It was developed ages ago by a small upstart company called Shopify. It solves a bunch of problems about how to let external parties (our clients) give us templates they’d like us to use for them (new themes) without any security implications (doing bad things to our app). So, we’re converting our existing code to support Liquid Templates. The made-up verb for this is “liquify” or perhaps “liquidify,” but my spell checker doesn’t like it.

From Tech Talk with Dr Nic Williams

Liquid Example
liquid
{%- if current_product != blank and current_product.pricing.hide_price? %}
    <script type="text/javascript">
        document.addEventListener('DOMContentLoaded', () => {
            const detailsSection = 
            document.querySelector('#SC-ProductDisplayDetails');
            
            if (detailsSection) {
                const header = detailsSection.querySelector('header');
                const block = '{{ all_content_blocks["hidden-price-apply"].render | j }}';
                const target = document.createElement('div'); 
                target.innerHTML = block;
                header.parentNode.insertBefore(target, header.nextSibling);
            }
            
        });
    </script>
{% endif %}

Results:

On the store, when on a product details page. We should see the New Dealer Application Fee product card Call to Action (CTA) in the details section (when we are not logged into the store).

Image of the Site Head Contentblock

Image of the dealer exclusive product with the apply now product card

6. Automating Dealer Membership Assignment

Let’s use this out-of-the-box StoreConnect functionality around the membership feature. When the user checkouts the Application Product. It will collect the personal details that is standard for storeconnect checkout, process the payment and ask them to set a password for their new dealer account login. We will configure StoreConnect to link Account, Membership and Pricebook records giving the new dealer access to pricing and the ability to place product orders with a exclusive pricing.

Results:

Membership record Account record with Membership and Pricebook Assigned Image of membership config

Image of Account with Membership Assigned

Image of logged in front end Product listings with dealer pricing and ability to order

7. Circumventing the Fee using a Promo Code.

Results:

Promotion records Image of Promotion config

Image of Promotion config

Image of Promotion config

Conclusion

In demonstrating this dealer application process on your B2B site it introduces a level of automation and efficiency that can significantly enhance your business operations should you want to fully automate your dealer membership process. By leveraging the capabilities of StoreConnect within the Salesforce ecosystem, you could further build on the application process with the automation capabilities of the Salesforce CRM to expand your dealer network.