Building a quote generator in HubSpot with discount display functionality

Hello everyone!

I’m working on creating a quote generator within HubSpot to simplify our billing process. I need to set up a totals section that shows discount details when applicable. Specifically, I want to display both the discount percentage (like “Discount: 5.00%”) and the corresponding monetary figure (such as “Discount value: €25.00”) on the same line.

Here’s what I have implemented so far, but something isn’t functioning right:

{% set SHOW_CONTRACT_VALUE = INCLUDE_FULL_AMOUNT %}

{% if SHOW_CONTRACT_VALUE %}
  {% set GROSS_TOTAL = QUOTE_TOTALS.amount|default(0)|float %}
  {% set VAT_TOTAL = QUOTE_TOTALS.vat_amount|default(0)|float %}
{% else %}
  {% set GROSS_TOTAL = QUOTE_TOTALS.initial_payment|default(0)|float %}
  {% if QUOTE_TOTALS.initial_vat is number %}
    {% set VAT_TOTAL = QUOTE_TOTALS.initial_vat|float %}
  {% else %}
    {% set VAT_TOTAL = 0.0 %}
    {% for item in QUOTE_ITEMS|default([]) %}
      {% set VAT_TOTAL = VAT_TOTAL + (item.vat_cost|default(0)|float) %}
    {% endfor %}
  {% endif %}
{% endif %}

{% set NET_TOTAL = GROSS_TOTAL - VAT_TOTAL %}

{% set TAX_DESCRIPTION = 'VAT Amount' %}
{% if DISPLAY_ITEM_TAXES and UNIFORM_TAX_RATE and SHARED_TAX_VALUE is not none %}
  {% set tax_rate = SHARED_TAX_VALUE|float %}
  {% set percentage = tax_rate > 1 and tax_rate or (tax_rate * 100) %}
  {% set TAX_DESCRIPTION = percentage|format_number(LOCALE, 0) ~ '% VAT' %}
{% endif %}

{% set discount_sum = 
  (QUOTE_TOTALS.discount|default(0)|float) +
  (QUOTE_TOTALS.total_reduction|default(0)|float)
%}
{% set REDUCTION_AMOUNT = discount_sum|abs %}

{% set ITEM_ORIGINAL = 0.0 %}
{% set ITEM_FINAL = 0.0 %}
{% for item in QUOTE_ITEMS|default([]) %}
  {% set quantity = (item.qty is number) and (item.qty|float) or 1.0 %}
  {% set unit_cost = item.unit_price|default(0)|float %}
  {% set original = quantity * unit_cost %}
  {% set final = item.total is number and (item.total|float) or original %}
  {% set ITEM_ORIGINAL = ITEM_ORIGINAL + original %}
  {% set ITEM_FINAL = ITEM_FINAL + final %}
{% endfor %}

{% set ITEM_REDUCTION = (ITEM_ORIGINAL - ITEM_FINAL) %}
{% if ITEM_REDUCTION < 0 %}{% set ITEM_REDUCTION = 0 %}{% endif %}

{% set FINAL_REDUCTION = REDUCTION_AMOUNT|round(2) > 0 and REDUCTION_AMOUNT or ITEM_REDUCTION %}

{% if (NET_TOTAL + FINAL_REDUCTION) > 0 and FINAL_REDUCTION > 0 %}
  {% set REDUCTION_PCT = (FINAL_REDUCTION / (NET_TOTAL + FINAL_REDUCTION)) * 100 %}
{% else %}
  {% set REDUCTION_PCT = 0 %}
{% endif %}

{% set SHOWS_REDUCTION = FINAL_REDUCTION|round(2) > 0 %}

I believe the issue may lie in my approach to calculating or displaying the discount values. Has anyone else experienced similar challenges with HubSpot’s template engine?

HubSpot’s quote templates are awful to debug. Don’t waste time fighting with template logic - move the calculation outside HubSpot entirely.

Set up a webhook that triggers when quotes are created or updated. Send the raw data to an automation platform that handles math with actual programming instead of janky template variables.

I built this exact solution last year. The automation grabs quote data, runs discount calculations with proper error handling, then pushes formatted results back to HubSpot custom fields. No more template debugging or float precision headaches.

You can add validation for edge cases like zero totals or negative discounts before they break anything. Plus you get real logging to see what’s happening at each step.

Takes about an hour to set up and saves weeks of template hell. Way better than forcing HubSpot’s template engine to do complex math.

your discount calculation’s breaking because you’re dividing by zero when totals hit zero. wrap that percentage calc in a better check - try {% if (NET_TOTAL + FINAL_REDUCTION)|round(2) != 0 %} instead. hubspot’s template engine gets wonky with float precision too, so run everything through |round(2) earlier in the chain, not just when displaying.

I ran into this exact same thing building quote templates in HubSpot. Your issue’s probably coming from the conditional logic around SHOW_CONTRACT_VALUE - it’s messing with how totals get calculated, which then breaks the discount percentage calculation. The discount percentage goes haywire when NET_TOTAL + FINAL_REDUCTION equals zero or when there’s a mismatch between gross/net totals in different scenarios. I’d temporarily add some debug output to see what you’re actually getting for NET_TOTAL, FINAL_REDUCTION, and REDUCTION_PCT at runtime. Also double-check that your QUOTE_TOTALS.discount and QUOTE_TOTALS.total_reduction values are actually populating - sometimes these fields are empty depending on how the quote was generated. That absolute value function on discount_sum might be hiding negative values that need different handling too.

Your VAT calculation logic is broken in the conditional branches. When INCLUDE_FULL_AMOUNT is false, you’re recalculating VAT by looping through quote items, but this doesn’t match how you’re getting gross and VAT totals elsewhere. This messes up your NET_TOTAL calculation and makes your discount percentage wrong.

I’ve hit this exact issue mixing HubSpot’s built-in quote totals with manual calculations. The QUOTE_TOTALS.initial_vat field sometimes returns formatted strings instead of raw numbers, which breaks your number check. Don’t default to zero and recalculate - try converting it explicitly with QUOTE_TOTALS.initial_vat|replace(',', '')|float to handle formatted currency.

Your discount logic has another problem: you’re assuming QUOTE_TOTALS.discount and QUOTE_TOTALS.total_reduction are the same type of reduction, but they’re usually not. One’s probably line-item discounts, the other’s quote-level adjustments. This double-counting completely throws off your percentage calculation.

you’re overcomplicating the discount display. I had the same issue and fixed it by simplifying the percentage calc - just use {% set REDUCTION_PCT = FINAL_REDUCTION > 0 ? ((FINAL_REDUCTION / ITEM_ORIGINAL) * 100) : 0 %} instead of adding reductions back to net total. hubspot’s quote engine handles most edge cases if you don’t fight it.

The issue is probably your ITEM_REDUCTION calculation logic. I ran into the same thing when I built something similar - HubSpot’s QUOTE_ITEMS array has inconsistent data types depending on the quote scenario. Your loop expects item.total to always work, but sometimes it’s null or undefined even when item.total passes the number check. I’d add explicit type conversion like {% set final = (item.total|default(original)|float) %} so you always get a numeric value. That negative check {% if ITEM_REDUCTION < 0 %} might be hiding legitimate negative discounts that need different handling. Try logging each item calculation to see if one line item is messing up your entire reduction sum. The template engine gets weird with array iterations when it hits mixed quote types.