Quotes and B2B
Turn the cart into a quote request that reaches Shopify as a draft order, and show business customers their company, their quantity rules and their prices.
With quotes, the cart does not go to checkout: it sends a request. You receive a draft order in Shopify, with the lines, variants and quantities the customer chose. You set your price, send the invoice, and the customer pays it in Shopify’s checkout. This page builds the quote cart and covers what Smootify shows to business (B2B) customers.
Note
Quotes need the Server plan and Draft Orders turned on in the Smootify dashboard. They run on the site’s licensed domain.
How it fits together
A quote is a cart. You build it as in Build the cart, then choose one of two ways:
| Way | Built with | Use it when |
|---|---|---|
| A quote cart | data-draft="true" on smootify-cart: every submit of its form sends a quote | the store sells only on quote, or on a quote page of its own |
| A quote button in a normal cart | a button with type="submit" and name="draft-order", next to the checkout button, which keeps working | some customers buy and others ask |
What Smootify needs:
- a
smootify-cartwith its<form>, as for any cart; - an
inputwhosenameisemail, so the draft order has an address to send the invoice to.
What is up to you: the layout, the other fields you ask for, and the texts. Write them as a request, not as an order.
1. Build a quote cart
<smootify-cart data-draft="true">
<div cart-condition="no-items-in-quote">Your quote is empty</div>
<form>
<cart-item>
<div cart-item="title">Product</div>
<div cart-item="variant-title">Red / M</div>
<quantity-input><button data-action="minus">-</button><input name="quantity"><button data-action="plus">+</button></quantity-input>
<button data-action="remove">Remove</button>
</cart-item>
<input name="email" type="email">
<button type="submit" data-wait="Sending…">Send request</button>
</form>
<div form-done hidden>Thank you. We will send you a quote by email.</div>
<div form-fail hidden>Something went wrong</div>
</smootify-cart>In a quote cart, [form-done] is not the empty cart: it shows once the request is sent. Two conditions work inside smootify-cart, cart-condition="items-in-quote" and cart-condition="no-items-in-quote". The cart’s four states:
| State | What shows |
|---|---|
| The quote has lines | the <form>: the lines, the email field and the submit button that sends the request; cart-condition="items-in-quote" shows |
| The request is sent | [form-done]: write it as “request received”, so the customer does not think they have bought; Smootify empties the cart, and cart-condition="no-items-in-quote" stays hidden |
| The quote is empty | cart-condition="no-items-in-quote", outside the form; the form and [form-done] are hidden, and smootify-cart has the class has-empty-quote |
| Shopify refuses the request | [form-fail], with Shopify’s errors, as in any cart |
2. Or add a quote button to a normal cart
In a cart without data-draft, add a button with type="submit" and name="draft-order", inside the <form> next to the checkout button. The email field goes in the same form.
<button type="submit" data-wait="Please wait…">Check out</button>
<button type="submit" name="draft-order">Ask for a quote</button>A link cannot do this: it does not submit the form. Use a button.
3. What the draft order holds
Each field of the form has its place in the draft order:
| In the quote cart’s form | In the draft order |
|---|---|
| the lines, each with its variant, quantity and properties (such as an engraving) | Products: the same lines, variants, quantities and properties |
an input with the name email | Customer: the Shopify customer with that email, created when there is none |
a textarea with the name note | Notes: the note of the draft order |
any other field, such as Company or Phone | Additional details, with the field’s name as the label |
| the currency the customer saw | the currency of the draft order |
- The lines keep their properties, such as an engraving or an uploaded file. A Magic Box arrives as the products inside it. A Shopify bundle arrives as its components, with a “Bundle” detail listing them.
- The customer is the Shopify customer with the email in the form. If there is none, Shopify creates one with that email. Without an email field, a logged-in customer’s account is used.
Subscription lines are left out: a draft order does not carry the selling plan. See Subscriptions.
4. Send the quote from Shopify
In your Shopify admin, the request is under Orders > Drafts, with the discount codes the customer had applied to the cart. Change the prices or add a discount, then send the invoice. The customer gets an email with a link to Shopify’s checkout, at the price you set. Discount codes can still be used there.
To get an email for each new request, import the ready-made Quote request notification workflow in the free Shopify Flow app. It reacts when a draft order is created: after importing it, replace the default email with the address that should receive the requests.
5. Business customers (B2B)
Shopify’s B2B features, with companies, catalogs and quantity rules, are on every paid Shopify plan. Outside Shopify Plus, a store can have at most 3 active B2B catalogs, and it needs Shopify’s new Markets: see Shopify’s B2B plans. When a customer who belongs to a company logs in with customer accounts, Smootify asks Shopify for products and the cart as that company’s buyer, using the company’s first location. The prices and quantity rules Shopify sets for that company then apply on the site.
Show the company. company="name" shows the name of the customer’s company, anywhere on the page. company-metafield="…" shows a metafield of the company, such as a customer code or the name of their sales contact, and if-company-metafield shows an element only when that metafield has a value. For a customer without a company, these elements are removed, and so are the if-company-metafield elements for a visitor who is not logged in. unless-company-metafield does the opposite: it shows its element when the company has no value for that metafield, and to guests, who have no company. Use it for the guest’s Add to cart next to the company’s Add to quote list. See customer attributes.
Show the quantity rules. Inside smootify-product:
variant="quantity-min": the smallest quantity that can be ordered;variant="quantity-max": the largest, hidden when there is no maximum;variant="quantity-increment": the pack size the quantity must be a multiple of.
Buy for some, quote for others. Put the quote button inside an element with customer-tagged="wholesale" (use your own tag). Only logged-in customers with that tag see it. Everyone else keeps the checkout button.
<button type="submit" data-wait="Please wait…">Check out</button>
<div customer-tagged="wholesale"><button type="submit" name="draft-order">Ask for a quote</button></div>To order the same list again later, customers can use Buy again on a past order: see Orders and buy again. For a minimum order value, or products sold in packs, use purchase rules.
Customers also see the quotes you send them in their account, with a link to pay each one: see Orders and buy again.
6. Volume prices for companies
A B2B catalog in Shopify can lower the price as the quantity grows: €10.00 each from 1, €9.00 from 10, €8.50 from 50. Smootify shows these price breaks as a table on the product page, and the price follows the quantity in the form. Volume prices need neither the Server plan nor Draft Orders.
Where the prices come from. In Shopify, you set the price breaks of a variant in the price list of a B2B catalog. Outside Shopify Plus, Shopify attaches that catalog to a B2B market made of the company’s locations. A catalog assigned directly to company locations is a Shopify Plus feature. Only the contacts of a company in that catalog get the breaks: guests and customers without a company see none.
Build the table. Inside smootify-product:
variant="price-breaks"on adivis the template of one row. Smootify repeats it once per row: the variant’s price from its minimum quantity, then each price break.- Inside the row,
price-break="range"writes1–9,10–49,50+.price-break="price"writes the price of one,"savings"the saving, such as-10%(hidden on the first row), and"total"the row’s first quantity at its price."min"and"max"write the row’s first and last quantity (maxis hidden on the last row). A row with none of these writes10+ €9.00. condition="has-price-breaks"on the section around it hides it for buyers without breaks.variant="price-at-quantity"on aspanwrites the price of one at the form’s quantity, and follows it.
<div condition="has-price-breaks">
<div variant="price-breaks">
<div price-break="range">1–9</div>
<div price-break="price">€10.00</div>
<div price-break="savings">-10%</div>
</div>
<div>Price each: <span variant="price-at-quantity">€10.00</span></div>
</div>A row is a choice. A click on a row sets the form’s quantity to the row’s first quantity. The row of the current quantity gets the class is-active: style it in the component’s CSS. For the click to work, the add-to-cart form needs its quantity field.
Add a row to the cart. Optionally, put a button with price-break="add" inside the row. It adds the row’s first quantity to the cart without changing the form’s quantity. It goes through the product’s smootify-add-to-cart, with its add-ons, so that form must be on the page. To make it read “Add 10”, write Add in it followed by an element with price-break="min": <button price-break="add">Add <span price-break="min"></span></button>.
Example: a café orders mugs at its company price
Click a row, its Add button or the quantity.
variant="price-breaks"One row, repeated once per price break. The row of the current quantity gets is-active, and a click sets the quantity to the row’s first quantity.price-break="range"1–9, 10–49, 50+.price-break="price"The price of one piece in that row.price-break="savings"The saving on the first row’s price. Hidden on the first row.price-break="total"The row’s first quantity at its price: 10 × €12.80.price-break="add"A button: “Add ” and price-break="min", the row’s first quantity. It adds that quantity to the cart, and the quantity field stays as it is.variant="price-at-quantity"The price of one piece at the form’s quantity. It follows the quantity.With purchase rules. The first row starts at the variant’s minimum: the higher of the B2B catalog’s minimum and the minimum of the purchase rules. Price breaks at or below that minimum are left out.
Before you publish
On your *.workers.dev address or in the dev server, press Alt⇧ ShiftD (⌥ Option⇧ ShiftD on a Mac) to turn on Smootify’s debugger, then send a test request and open it in Shopify.
Check these first
- The draft order has no email. The field’s
nameis not exactlyemail. Set thenameback toemail. - The quote cart goes to checkout. Draft Orders is not available on this page: check the Server plan, that Draft Orders is turned on in the dashboard, and that the page is on the licensed domain. Without it, Smootify turns a quote cart back into a normal cart, and a quote button does nothing.
- Customers think they have ordered.
[form-done]still reads like an order confirmation. Rewrite it as a request received. - “Your quote is empty” never shows. The element with
cart-condition="no-items-in-quote"is inside the<form>, which is hidden while the cart is empty. Move it outside the form, insidesmootify-cart. - The quote button opens a page or does nothing. It is a link. Use a
buttonwithtype="submit". - A subscription is missing from the draft order. Smootify leaves subscription lines out of a quote.
- The volume price table never shows. The customer is not a contact of a company whose B2B catalog has price breaks for that variant. Outside Shopify Plus, the catalog must be attached to a B2B market of the company’s locations.