Africa Conglomerate ← All Guides

💰 Pricing Setup

⏱ 12 min read 📋 7 steps 🎯 Beginner 👥 B2B Sellers & Admins

Learn how to configure prices for your products correctly — including setting retail and wholesale tiers, handling multiple currencies, using quantity-break discounts, and understanding why a product might appear to have a price but still fail to add to cart.

Before you begin
  • At least one product must exist in your catalog (see Catalog Management)
  • You must have a B2B account with Seller or Admin role
  • Know your selling currency — every price row carries its own currency, and your Company profile's default currency is used when the platform looks prices up for buyers from your own organisation
Two kinds of price row
  • Base price — for Agricultural Products and Arts & Crafts products this is the retail / minimum-quantity-1 row created automatically from the Price and Currency fields on the vertical product form. It shows an Auto-synced badge on the pricing panel, is rewritten every time the product is saved in the vertical app, and cannot be deleted from the panel. For General Commerce products the first price row comes from the Default Price field on the catalog form (or is added on the panel).
  • Tier rows — wholesale, VIP and volume bands. Added, edited and deleted on the shared pricing panel for every product, whichever vertical it belongs to.

Part 1 — How Pricing Works

Each product can have multiple Price records. The platform picks the best matching price at checkout using a 5-step resolution process. Understanding this prevents the most common setup mistakes.

💡 Key concept: a price record has five dimensions
FieldWhat it controlsCommon mistake
currency Which currency this price is expressed in (e.g. UGX, USD, KES) Setting currency to USD but your company's default is UGX — the price is found but the label shows the wrong currency
customer_tier retail (B2C buyers), wholesale (B2B buyers), or vip Only setting a wholesale price — B2C buyers can't add to cart
min_quantity Minimum order quantity for this price to apply Setting min_quantity=10 on the only price — adding 1 unit fails because no price applies
valid_from / valid_until Date window when this price is active (blank = always active). Not editable on the pricing panel — only a platform administrator can set these in the Django admin Setting valid_until in the past — the price appears in admin but is invisible to buyers
is_active Master on/off switch for the price record Accidentally deactivating the only price for a product

How the platform finds a price at checkout

When a buyer adds a product to cart, the platform tries these steps in order and stops at the first match:

1

Exact match — buyer's currency + buyer's tier

e.g. a UGX retail price for a retail buyer. Best case — always aim for this.

2

Same currency, retail tier (tier downgrade)

A B2B wholesale buyer gets the retail price when no wholesale price exists in their currency.

3

Any currency + buyer's tier

A US buyer (USD context) can still purchase a UGX-priced product. The price is shown in UGX with an automatic conversion displayed for reference.

4

Any currency + retail (last sensible fallback)

Wholesale buyer, wrong currency — still finds a retail price to fall back on.

5

Absolute last resort — any active price at all

VIP-only prices, exotic currencies — if anything active exists, it is used.

⚠️ When all 5 steps fail
If no valid active price is found for the requested quantity, the platform raises a "has no price configured" error at add-to-cart. See Part 5 — Diagnosing Price Problems for how to fix this.

Part 2 — Adding Your First Price

Every product needs at least one active retail price before buyers can add it to cart.

1

Open the product's pricing panel

  • General Commerce: go to Catalog → Products (/catalog/products/), click the product, then click Manage Pricing (/catalog/products/<id>/pricing/).
  • Agricultural Products / Arts & Crafts: open the product's edit page in the vertical app (/agriproducts/<id>/edit/ or /arts_en_crafts/<id>/edit/) and switch to the Pricing tab. The base price is already there — it comes from the Price and Currency fields on the Details tab. If you see "Save the product first to enable tier pricing", save the Details tab once and come back.
📸 Screenshot: Product Pricing Tab Shows the product edit page with the Pricing tab highlighted and an empty prices table. /static/guides/images/pricing/01-pricing-tab.png Screenshot: Product Pricing Tab
2

Click Add Tier

Vertical products already have this row — it is the auto-synced base price, so skip to Part 3. For a General Commerce product without a price yet, fill in the Add Price Tier form with these values for a standard single retail price:

FieldValueNotes
CurrencyUGX (or your local currency)Must match your company's default currency for step-1 resolution
Customer TierRetailRequired so B2C buyers can purchase. Add a separate wholesale row later for B2B pricing.
Unit Pricee.g. 45000The price per single unit
Minimum Quantity1⚠️ Must be 1 for a standard price. Higher values mean the price only activates for bulk orders.

Click Save Tier. New rows are created active with no date window; the message "Price tier added." confirms it (or "Price tier updated." if a row with the same currency, tier and minimum quantity already existed — its unit price is overwritten). To change a row later, click its pencil Edit button: you can change the unit price, minimum quantity and the Active switch, then Save Changes.

📸 Screenshot: Add Price Form Shows the Add Price Tier modal with Currency=UGX, Customer Tier=Retail, Unit Price=45000, Minimum Quantity=1. /static/guides/images/pricing/02-add-price-form.png Screenshot: Add Price Form
3

Verify the price is live

Open your product in the shop (Browse Products in the sidebar, or /catalog/shop/) and confirm the price is displayed. Try adding 1 unit to cart to confirm end-to-end.

Part 3 — Adding Wholesale (B2B) Pricing

B2B buyers are automatically assigned the wholesale tier. Add a separate price row to give them a discounted rate. If no wholesale price exists, the platform falls back to the retail price — B2B buyers can always purchase.

1

Add a second price row with tier = wholesale

Click Add Tier on the same product's pricing panel and set:

FieldValue
CurrencySame as your retail / base price (e.g. UGX)
Customer TierWholesale
Unit PriceYour discounted B2B rate, e.g. 38000
Minimum Quantity1 (or higher if the discount only applies for bulk)

Click Save Tier. The new row appears in the Price Tiers table immediately; the base price card is unchanged. On a vertical edit page you are returned to the Pricing tab.

💡 Result with both rows configured
  • B2C buyer adds 1 unit → pays UGX 45,000 (retail)
  • B2B buyer adds 1 unit → pays UGX 38,000 (wholesale)

Part 4 — Quantity Break Discounts

Use multiple price rows with different min_quantity values to automatically apply bulk discounts. The platform always selects the row with the highest min_quantity that still fits the buyer's order quantity.

📋 Example: 3-tier bulk pricing for a retail buyer
RowTierMin QtyUnit PriceWhen applied
1retail1UGX 45,000Orders of 1–9 units
2retail10UGX 40,000Orders of 10–49 units
3retail50UGX 35,000Orders of 50+ units

⚠️ Always include a row with min_quantity=1. If your smallest row has min_quantity=10, a buyer adding 5 units will get a "no price configured" error even though prices clearly exist in the admin.

Part 5 — Diagnosing "No Price Configured" Errors

You see a price listed on the product page but the buyer gets an error when adding to cart. This happens when the price record exists but fails all five resolution steps. Here are the common causes and fixes:

Symptom Root cause Fix
Error on add-to-cart for qty=1, price visible in admin min_quantity is set to something greater than 1 on all price rows Add a new price row with min_quantity = 1
Price visible on the pricing panel but not in shop is_active = False on the price record (row shows an Inactive badge) Click the row's pencil Edit button, switch Active on, Save Changes
Price worked last week, fails now valid_until date has passed (shown in the Valid Until column) Ask a platform administrator to update or clear valid_until in the Django admin, or add a fresh tier row
Price set up but not activating yet valid_from is in the future Ask a platform administrator to clear or backdate valid_from in the Django admin
Vertical product shows "No base price" in Catalog → Products, or "No Price" on the vertical list The product was saved with price 0 (or no currency), so no base price row was created Edit the product in the vertical app, enter a non-zero Price and Currency, click Update Product
Delete button on the base price row is greyed out / "The base price cannot be deleted" error The base price row is owned by the vertical app Change the price on the product's Details tab and save — it is re-synced automatically
B2C buyer gets error, B2B buyer is fine Only a wholesale tier price exists — no retail row Add a separate price row with customer_tier = retail
Price shows correctly in shop but Order Summary shows wrong currency Product price currency does not match company default currency Check your Company profile currency matches the currency code on your price records
🛠️ Run the built-in price diagnostics tool
Platform administrators can scan all products for price configuration issues from the Render shell:
python manage.py check_product_prices

To check a single product:

python manage.py check_product_prices --product-id 42

To automatically reactivate prices that are inactive but otherwise valid:

python manage.py check_product_prices --fix-inactive
The tool reports BLOCKING problems (will fail add-to-cart), warnings (prices expiring soon), and an OK summary for healthy products.

Part 6 — Multi-Currency & International Buyers

As a seller you set prices in your local currency (e.g. UGX). International buyers automatically see a converted price for reference alongside your original price. You do not need to create separate price records for each currency.

💡 How it works
  • Exchange rates are refreshed daily from Open Exchange Rates.
  • On the shop listing: UGX 45,000 with ≈ USD 12.20 shown below in smaller text.
  • On the product detail page: an "Approx." line below the headline price with the buyer's currency and a conversion badge (e.g. UGX → USD).
  • In the cart Order Summary: an indicative total in the buyer's currency with the note "actual charge in UGX".
  • The actual transaction is always processed in the seller's currency. The conversion is informational only.
  • If no FX rate is available for a pair (e.g. an obscure currency), the converted line is simply hidden — no error is shown.
⚠️ Setting your company currency correctly matters
Go to Settings → Company Profile → Default Currency and set it to the currency your prices are denominated in (e.g. UGX for Uganda, KES for Kenya, USD for USD-denominated businesses). This currency is used as the cart total label and the FX conversion base. Mismatched settings cause the Order Summary to show the wrong currency code on the correct number.

Part 7 — Promotional & Time-Limited Prices

valid_from and valid_until can schedule promotional pricing without touching your standard price row. These two dates are not editable on the pricing panel — a platform administrator must set them in the Django admin (Catalog → Prices). Sellers without admin access should use the Active switch approach in step 3 instead.

1

Keep your standard price row intact

Never edit the dates on your permanent price row. Instead, create a second price row with the promotional rate.

2

Add a promotional price row

FieldValue
CurrencySame as standard price
Customer Tierretail (or wholesale)
Unit PriceYour promotional rate, e.g. 35,000
Min Quantity1
Valid FromPromotion start date/time
Valid UntilPromotion end date/time
Active✓ ticked
3

How the platform handles the overlap

During the promotional window, both rows are valid. The platform selects the row with the highest min_quantity that still applies — if both rows have min_quantity=1 the choice between them is not guaranteed, so do not rely on two overlapping rows.

Simplest reliable approach: on the pricing panel, click the standard row's pencil Edit button, switch Active off and Save Changes for the promo window, then switch it back on afterwards. For vertical products the base price row is re-activated automatically the next time the product is saved in the vertical app, so change the base price on the Details tab instead of deactivating it.

Quick Reference — Price Setup Checklist