Skip to content
Log in

Display product approvals in the account area

On this page

When you sell restricted products, each approval is a record against a customer’s Account. The account page can show those approvals back to the customer, so they know what they are cleared to buy, how much of their allowance is left, and when it runs out.

The base theme ships this section already. Use this process when you want to change what it shows, or add the approvals link to your account menu.

Before you start

The section already exists

The account page reads current_request.params.section and renders one snippet per section. Product approvals is one of the sections the base theme registers:

Section URL Snippet
product_approvals /account?section=product_approvals account/product_approvals

The router clause looks like this:

```liquid

{%- when “product_approvals” %} {% render “account/product_approvals”, identifier: identifier %} ```

snippets/account/product_approvals is only a dispatcher: it renders product_approvals/index for the list and product_approvals/show for a single approval.

Override snippets/account/product_approvals/index, not the dispatcher. Replacing the dispatcher removes the detail page along with the list, and you do not need to touch the router either way.

Where the data comes from

Approvals hang off the Account, not the Contact. The account page provides both current_customer (the signed-in Contact) and current_account (their Account), so read approvals from current_account.

Liquid Type Notes
current_account.product_approvals List[ProductApproval] The approvals belonging to this Account

Each entry is a ProductApproval drop, which renders the s_c__Permitted_Restricted_Product__c record. These are the attributes worth surfacing:

Attribute Type Notes
approval_status String One of approved, completed, expired, pending, or none. Prints as text, but reaches Liquid as a symbol, so cast it to a string before comparing it
product Product The approved product, when the approval is for a single product
product_category ProductCategory The approved category, when the approval covers a whole category
approved_quantity Number The maximum quantity this approval allows
purchased_quantity Number The quantity already bought on completed orders
pending_quantity Number The quantity already bought on submitted orders that have not completed
remaining_quantity Number The unused quantity still available
unlimited? Boolean True when the approval has no quantity limit
approved_from Timestamp When the approval starts, as a UTC timestamp
approved_until Timestamp When the approval ends, as a UTC timestamp
order_items List[OrderItem] The order items bought against this approval

:::note An approval is granted at product level or at category level, so one of product and product_category is blank on any given record. Check which one is populated rather than assuming product is always there, or the row renders with an empty name. :::

Build the section

This snippet lists the customer’s approvals, handles both product and category approvals, and shows remaining quantity only where the approval is limited.

```liquid

Product approvals

{%- assign approvals = current_account.product_approvals %}

{%- if approvals.size > 0 %}

{%- for approval in approvals %} {%- endfor %}
Approved for Status Remaining Expires
{%- if approval.product != blank %} {{ approval.product.name }} {%- elsif approval.product_category != blank %} {{ approval.product_category.name }} {%- else %} Approval {%- endif %} {{ approval.approval_status }} {%- if approval.unlimited? %} Unlimited {%- else %} {{ approval.remaining_quantity }} of {{ approval.approved_quantity }} {%- endif %} {%- if approval.approved_until != blank %} {{ approval.approved_until | date: "%b %-d, %Y", timezone: current_store.timezone }} {%- else %} No expiry {%- endif %}

{%- else %}

You have no product approvals.

{%- endif %} ```

Pass a timezone when you format these dates. approved_from and approved_until are UTC, so formatting them without timezone: can render a date a day out for customers whose local date differs from UTC, which matters most on the expiry date a customer is reading to decide whether to order today.

The markup above uses a plain table so it inherits your own styles. For how theme assets and stylesheets are loaded, see Theme assets and styling.

Add the section to the account menu

Both snippets/account/menu and snippets/header/dropdown/account already show this link when the account has approvals, so there is usually nothing to add. Override one of them when you want to change the wording or where the entry sits, not to create it.

The existing entries are conditional for a reason, so keep the guard when you change one, or retail customers see a link to an empty page:

```liquid

{%- if current_account.product_approvals.size > 0 %} Product approvals {%- endif %} ```

For the full account menu structure and how to add your own sections, see Add a custom page to the account page menu.

Show approval status on the product page

The same data is useful on the product page itself, where a customer is deciding whether to buy. Do not loop the account’s approvals to find it: the product drop already carries the answer, and it accounts for approvals granted at category level, which a loop matching on product id would miss.

Liquid Returns
product.approval_status This customer’s status for this product: approved, completed, expired, pending, or none. Cast it to a string before comparing it.
product.current_approved_quantity The maximum quantity this customer may buy. Returns Infinity when the approval is unlimited, and when the product is not restricted at all.
product.pending_approval_date When a pending approval starts, or blank

:::warning Two things here fail silently rather than raising an error.

approval_status reaches Liquid as a symbol, not a string. Comparing it directly, as product.approval_status == "approved", is always false, so the message never renders and nothing tells you why. Cast it first. Printing it with {{ }} is unaffected.

current_approved_quantity returns Infinity for an unlimited approval. Printing it unguarded shows the customer the word “Infinity” where a number should be. :::

```liquid

{%- assign approval_state = product.approval_status cast: “string” %}
{%- assign approved_quantity = product.current_approved_quantity cast: “string” %}

{%- if approval_state == “approved” %} {%- if approved_quantity == “Infinity” %} <p class="SC-Notice">You are approved to buy this item.</p> {%- else %} <p class="SC-Notice">You can buy up to {{ approved_quantity }} of this item under your current approval.</p> {%- endif %} {%- elsif approval_state == “pending” and product.pending_approval_date != blank %}

Your approval for this item starts {{ product.pending_approval_date | date: "%b %-d, %Y", timezone: current_store.timezone }}.

{%- endif %} ```

Both attributes aggregate a product-level and a category-level approval, so this is correct where a loop over product_approvals would silently show nothing to a customer approved by category. See the cast filter.

:::warning Do not treat what you render here as an access control. Whether a customer can actually buy a restricted product is enforced by StoreConnect when the order is placed, and the approval fields are for informing the customer, not for gating the purchase. Rendering an encouraging message does not grant permission, and hiding one does not remove it. :::

Once the section is in place, an approved customer visiting /account?section=product_approvals sees each approval with its status, its remaining quantity, and its expiry date.

Was this article helpful?

Was this article helpful?