No. Evaluations are cached with the version-hash pattern also used for company pages: the key combines the listing ID, a hash of the active rule set and a hash of the market context, so a change to either produces a new key. Normal traffic is cache hits; a rule change causes a short burst of misses, each recomputed in well under a millisecond.
The pricing engine that retired Monday's spreadsheet
Every Monday morning, a developer at a B2B marketplace opened a shared spreadsheet, copied the week's price multipliers into a management command and ran it against production. Two hundred listing categories depended on that ritual. It kept prices three to seven days stale, and once it put premium listings online at ten times their price.
Services
Backend Engineering, Product
Industry
B2B Marketplace
Year
2023-2024
THE CHALLENGE
Six hours at ten times the price
The spreadsheet was the pricing system. Account managers typed multipliers into it during the week; the developer imported them on Monday. Nobody could see what a change would do before it was live, and typos went straight to buyers. The worst case was a seasonal multiplier entered as 12.5 instead of 1.25: premium listings sat at ten times their intended price for six hours before anyone noticed. Between incidents the process was merely slow: a market that moved on Tuesday was priced the following Monday.
THE SOLUTION
Rules as data, evaluated in order
The engine treats pricing rules as data. Each rule is a database record with a priority and a handler class whose apply() receives the current price and the market context and returns a new price. Account managers edit them in Django admin: a demand threshold, a supply floor, a seasonal modifier. A published change is live immediately, with no deploy. That freedom is also the risk: a rule set nobody reviews can do the same damage as the spreadsheet, faster, which is why the engine ships with a preview mode, price bounds per category and an evaluation log. A third-party pricing product was rejected: those tools are built for millions of SKUs and competitor price scraping, while this marketplace prices 200 categories on regional demand patterns, equipment condition grades and seasonal industry cycles that no off-the-shelf tool models.
The pipeline. Each rule sees the previous rule's output; clamp and log come last:
Python
class PricingEngine:
def evaluate(self, listing, context):
"""Evaluate all active rules in priority order."""
price = listing.base_price
log = []
rules = PricingRule.objects.filter(
is_active=True,
category=listing.category,
).order_by('priority')
for rule in rules:
handler = rule.get_handler()
old_price = price
price = handler.apply(price, context)
log.append({
'rule': rule.name,
'input': old_price,
'output': price,
'delta': price - old_price,
})
# Clamp to category bounds
price = max(listing.category.price_floor, price)
price = min(listing.category.price_ceiling, price)
PriceEvaluation.objects.create(
listing=listing,
base_price=listing.base_price,
final_price=price,
rules_applied=log,
context=context,
)
return pricePreview a rule change
The draft opens with the peak markup raised from 25 % to 40 %. Compare the columns, then publish or discard. Push demand up and supply down until the ceiling clamps the draft, and watch the composed adjustment outgrow the largest single rule.
Rule engineUnpublished changes
Market context
Evaluation pipeline
| Rule | Published | Draft |
|---|---|---|
| Base price | €120.00 | €120.00 |
| Demand surge+1 % per demand point above the threshold | ×1.15€138.00 | ×1.15€138.00 |
| Low inventory+1 % per supply point below the floor | ×1.00€138.00 | ×1.00€138.00 |
| Seasonal modifierPeak season only. Off-peak is fixed at -15 % | ×1.25€172.50 | ×1.40€193.20 |
| Clamp€60.00 - €300.00 | ×1.00€172.50 | ×1.00€193.20 |
| Final price | €172.50 | +12%€193.20 |
Price across the demand range
+61%Composed adjustment
+40%Largest single rule
2Evaluations logged
0Rule sets published
A rule handler. The threshold and the rate are configuration, the math is code:
Python
class DemandSurgeRule(BasePricingRule):
"""Increase price when demand exceeds threshold."""
def apply(self, price, context):
demand = context.get('demand_percentile', 50)
if demand > self.config['threshold']:
surplus = demand - self.config['threshold']
multiplier = 1 + (surplus * self.config['rate'])
return round(price * multiplier, 2)
return priceSafeguards
When a rule is wrong
Preview mode. A rule in preview is evaluated on every computation and logged, but the live price does not change; the admin shows live and projected price side by side, per listing. 'What will this rule actually do' is answered before publishing.
Bounds. Every category has a floor and a ceiling, applied once after the last rule, so no combination of rules can push a price outside them. Three rules compounding to a 200 % markup still stop at the ceiling; an off-peak discount never crosses the floor into negative margin.
The log. Each computation is stored as a PriceEvaluation record: listing, base price, every rule that fired with its own delta, final price. When a buyer questions a price, support reads that record instead of reconstructing the week's rules.
THE RESULT
What changed on Monday morning
Nothing happens on Monday morning now. Account managers edit rules when the market moves, preview them against live prices and publish the same day. In the first six months, preview mode stopped 14 misconfigured rules before they reached buyers. The spreadsheet era produced roughly one pricing incident a month; there has been none since launch. Support settles a disputed price from the evaluation log in about three minutes instead of 45. Revenue per listing rose in the first quarter after launch, and the engine now prices 200 categories without anyone copying a number.
KEY METRICS
+18%Revenue per listing, first quarter after launch
0Pricing incidents since launch
50kPrice evaluations per day
CLIENT FEEDBACK
"I change a rule in the admin, check the preview next to the live price, and publish. Nobody waits for Monday any more, and I have not asked a developer to run an import since the launch."
Head of Sales
B2B Marketplace · Commercial
FOR YOUR PROJECT
- When it applies
Prices change on a schedule or by hand, and the people who own them cannot ship a change without a developer. The same shape fits fees, commissions and discounts.
- What to check
How a price is computed today. If two adjustments can apply at once, decide whether they stack or override, and write that down before any code exists.
- What it needs
A rules table with a priority field, an admin to edit it, a preview path and an evaluation log. Here that was Django and PostgreSQL, no new infrastructure, as a backend and product engagement over 2023-2024.
FAQ
TECHNOLOGY STACK
Django
Python
PostgreSQL
Dietmar Eglhofer - CEO, Solvster & VIARESDaniel made a decisive contribution to the founding and implementation of the companies Solvster and VIARES. He was responsible for the entire technical setup of the online presence, including server setups, developing and optimizing the website, and ensuring functionality. I was particularly impressed by how proactively and solution-oriented he always worked on improvements. Daniel was always very responsive and reliable - it was a pleasure working with him. His expertise and commitment contributed significantly to the success of both projects!
Follow in the footsteps of Dietmar and bring your vision to life.
Open to new ProjectsGet In Touch