A surprising number of wholesale and B2B companies still operate on the same system: a PDF catalog emailed to dealers, orders placed over the phone, and pricing negotiated per account. It works, but it doesn't scale. I built a platform to replace this entire workflow for a commercial refrigeration vendor, and the biggest challenge wasn't the code.
The Real Problem Isn't Technology
The hard part of digitizing a B2B operation is modeling the business logic that lives in people's heads. The sales team knows that Dealer A gets 15% off, Dealer B gets 20% off on coolers but standard pricing on parts, and that one guy in Florida gets a special rate because he's been ordering since 2003.
Before writing any code, I spent time mapping out every pricing rule, product relationship, and ordering workflow. The discovery phase is the project.
Modeling Product Hierarchies
Commercial refrigeration isn't simple. You have categories, subcategories, models with different specs, and accessories that only fit certain units. I structured this as a flexible catalog system:
// Product with specs and category relationships
type Product = {
id: string;
name: string;
category: "coolers" | "freezers" | "parts" | "accessories";
subcategory: string;
specs: Record<string, string>; // dimensions, voltage, capacity, etc.
compatibleWith: string[]; // product IDs this accessory fits
basePrice: number;
images: string[];
};
The specs field is intentionally generic. Every product category has different relevant specifications, and a rigid schema would break the first time the client wanted to add a new product type.
Tiered Pricing for Dealer Levels
The pricing model was the most complex piece. Different dealer tiers see different prices, and some products have custom overrides per account:
async function getDealerPrice(productId: string, dealerId: string) {
// Check for account-specific override first
const override = await db.priceOverride.findFirst({
where: { productId, dealerId },
});
if (override) return override.price;
// Fall back to tier-based pricing
const dealer = await db.dealer.findUnique({ where: { id: dealerId } });
const product = await db.product.findUnique({ where: { id: productId } });
const tierDiscount = {
gold: 0.20,
silver: 0.15,
standard: 0.10,
}[dealer.tier];
return product.basePrice * (1 - tierDiscount);
}
Account-specific overrides take priority. Then tier-based discounts. Then base price. This three-layer system captured every pricing scenario the sales team described.
Quote Requests Instead of Shopping Carts
B2B buyers don't add to cart and checkout with a credit card. They request quotes, negotiate terms, and place orders on net-30 accounts. I replaced the traditional cart with a quote request system:
// Quote request - replaces traditional checkout
async function submitQuoteRequest(items: QuoteItem[], dealerId: string) {
const quote = await db.quote.create({
data: {
dealerId,
status: "pending",
items: {
create: items.map((item) => ({
productId: item.productId,
quantity: item.quantity,
unitPrice: item.dealerPrice, // pre-calculated tier price
})),
},
expiresAt: addDays(new Date(), 30),
},
});
// Notify sales team
await sendQuoteNotification(quote);
return quote;
}
The sales team gets notified instantly, reviews the quote, and can approve, modify, or follow up. The entire back-and-forth that used to happen over email and phone now has a paper trail and a status.
Key Takeaways
- Map the business logic before writing code. The pricing rules and workflows that live in spreadsheets and people's heads are the real specification.
- Build flexible data models. B2B product catalogs change constantly. Rigid schemas become maintenance nightmares.
- Replace the workflow, not just the catalog. A digital PDF is still a PDF. Build the ordering and communication layer too.
- Start with quote requests, not payments. Most B2B transactions don't happen through online checkout.
This platform was built for International Coolers, a commercial refrigeration wholesale vendor. It replaced their PDF-and-phone workflow with a searchable catalog and structured quote system that runs 24/7.