From 09e3c13eaf5ed70565aeec1b688132a63fa18a03 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 30 Oct 2025 13:00:13 +0100 Subject: [PATCH] Fix pricing calculation by passing pricePerTon from frontend to backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backend was using a hardcoded PORTFOLIO_PRICING map that only had prices for portfolios 1, 2, 3 (defaulting to $18/ton for others). When Wren API returns Portfolio ID 37 at $237/ton, the backend was calculating with $18/ton instead, causing massive pricing discrepancies. Changes: - Frontend now passes pricePerTon (from Wren API) in checkout request - Backend uses the received pricePerTon instead of lookup table - Removed dependency on hardcoded PORTFOLIO_PRICING map - Added validation for pricePerTon parameter Example fix: - Before: 0.03 tons × $18/ton = $0.54 (wrong!) - After: 0.03 tons × $237/ton = $7.11 (correct!) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- server/routes/checkout.js | 19 ++++++++++++------- src/api/checkoutClient.ts | 1 + src/components/OffsetOrder.tsx | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/server/routes/checkout.js b/server/routes/checkout.js index 240ce75..2422d2d 100644 --- a/server/routes/checkout.js +++ b/server/routes/checkout.js @@ -17,11 +17,10 @@ const PROCESSING_FEE_PERCENT = 0.03; // 3% /** * Calculate pricing with processing fee * @param {number} tons - Number of tons - * @param {number} portfolioId - Portfolio ID + * @param {number} pricePerTon - Price per ton from Wren API * @returns {Object} Pricing breakdown */ -function calculatePricing(tons, portfolioId) { - const pricePerTon = PORTFOLIO_PRICING[portfolioId] || 18; // Default to $18/ton +function calculatePricing(tons, pricePerTon) { const baseAmount = Math.round(tons * pricePerTon * 100); // Convert to cents const processingFee = Math.round(baseAmount * PROCESSING_FEE_PERCENT); const totalAmount = baseAmount + processingFee; @@ -40,7 +39,7 @@ function calculatePricing(tons, portfolioId) { */ router.post('/create-session', async (req, res) => { try { - const { tons, portfolioId, customerEmail } = req.body; + const { tons, portfolioId, pricePerTon, customerEmail } = req.body; // Validation if (!tons || tons <= 0) { @@ -53,10 +52,16 @@ router.post('/create-session', async (req, res) => { return res.status(400).json({ error: 'Invalid portfolio ID' }); } - console.log(`📦 Creating checkout for portfolio ID: ${portfolioId}, tons: ${tons}`); + // Validate price per ton + if (!pricePerTon || pricePerTon <= 0) { + console.error('❌ Invalid pricePerTon received:', pricePerTon); + return res.status(400).json({ error: 'Invalid price per ton' }); + } - // Calculate pricing - const { baseAmount, processingFee, totalAmount, pricePerTon } = calculatePricing(tons, portfolioId); + console.log(`📦 Creating checkout for portfolio ID: ${portfolioId}, tons: ${tons}, price: $${pricePerTon}/ton`); + + // Calculate pricing using the price from frontend (Wren API) + const { baseAmount, processingFee, totalAmount } = calculatePricing(tons, pricePerTon); // Create line items for Stripe const lineItems = [ diff --git a/src/api/checkoutClient.ts b/src/api/checkoutClient.ts index f85c6fd..c5460d2 100644 --- a/src/api/checkoutClient.ts +++ b/src/api/checkoutClient.ts @@ -17,6 +17,7 @@ const getApiBaseUrl = (): string => { export interface CreateCheckoutSessionParams { tons: number; portfolioId: number; + pricePerTon: number; // Price per ton from Wren API customerEmail?: string; } diff --git a/src/components/OffsetOrder.tsx b/src/components/OffsetOrder.tsx index 981f283..f53083a 100644 --- a/src/components/OffsetOrder.tsx +++ b/src/components/OffsetOrder.tsx @@ -150,6 +150,7 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr const checkoutSession = await createCheckoutSession({ tons: actualOffsetTons, portfolioId: portfolio.id, + pricePerTon: portfolio.pricePerTon || 18, // Pass the actual price from Wren }); logger.info('[OffsetOrder] Checkout session created:', checkoutSession.sessionId);