From e8d47f0fb372f2172b3213c27f2a2c190c1e45c6 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 30 Oct 2025 14:17:14 +0100 Subject: [PATCH] Fix pricing discrepancy: use rounded-up price in Stripe checkout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem - Calculator displayed rounded-up price per ton (e.g., $238/ton) - Stripe checkout used exact Wren API price (e.g., $237.20/ton) - This caused confusion when checkout amount differed from calculator Example with 20,000 liters (53.9 tons): - Calculator showed: 53.9 × $238 = $12,819 - Stripe charged: 53.9 × $237.20 = $12,775.35 ## Solution Modified both OffsetOrder.tsx and MobileOffsetOrder.tsx to: - Keep displaying rounded-up price (Math.ceil) to users - Pass roundedPricePerTon to Stripe checkout session - Ensures calculator and Stripe always match exactly ## Changes - OffsetOrder.tsx (line 170): Pass roundedPricePerTon to createCheckoutSession - MobileOffsetOrder.tsx (lines 207-218): Add rounding to price display and calculations Now the price users see is exactly what they pay. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/MobileOffsetOrder.tsx | 7 +++++-- src/components/OffsetOrder.tsx | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/MobileOffsetOrder.tsx b/src/components/MobileOffsetOrder.tsx index 8a84124..22bc21e 100644 --- a/src/components/MobileOffsetOrder.tsx +++ b/src/components/MobileOffsetOrder.tsx @@ -204,7 +204,8 @@ export function MobileOffsetOrder({ tons, monetaryAmount, onBack }: Props) { const renderPortfolioPrice = (portfolio: Portfolio) => { try { - const pricePerTon = portfolio.pricePerTon || 18; + // Get the price per ton from the portfolio and round UP to next whole number + const pricePerTon = Math.ceil(portfolio.pricePerTon || 18); return formatCurrency(pricePerTon, currencies.USD); } catch (err) { console.error('Error formatting portfolio price:', err); @@ -212,7 +213,9 @@ export function MobileOffsetOrder({ tons, monetaryAmount, onBack }: Props) { } }; - const offsetCost = monetaryAmount || (portfolio ? actualOffsetTons * (portfolio.pricePerTon || 18) : 0); + // Calculate offset cost using the portfolio price (rounded UP to match display) + const roundedPricePerTon = portfolio ? Math.ceil(portfolio.pricePerTon || 18) : 18; + const offsetCost = monetaryAmount || (portfolio ? actualOffsetTons * roundedPricePerTon : 0); const handleInputChange = (field: keyof typeof formData, value: string) => { setFormData(prev => ({ ...prev, [field]: value })); diff --git a/src/components/OffsetOrder.tsx b/src/components/OffsetOrder.tsx index becbcee..6368e38 100644 --- a/src/components/OffsetOrder.tsx +++ b/src/components/OffsetOrder.tsx @@ -167,7 +167,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 + pricePerTon: roundedPricePerTon, // Pass the rounded-up price that matches calculator display }); logger.info('[OffsetOrder] Checkout session created:', checkoutSession.sessionId); @@ -188,13 +188,13 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr return formatCurrency(pricePerTon, currencies.USD); } catch (err) { console.error('Error formatting portfolio price:', err); - return formatCurrency(18, currencies.USD); // Updated fallback + return formatCurrency(18, currencies.USD); } }; - // Calculate offset cost using the portfolio price (rounded UP) + // Calculate offset cost using the portfolio price (rounded UP to match display) const roundedPricePerTon = portfolio ? Math.ceil(portfolio.pricePerTon || 18) : 18; - const offsetCost = monetaryAmount || (portfolio ? Math.ceil(actualOffsetTons * roundedPricePerTon) : 0); + const offsetCost = monetaryAmount || (portfolio ? actualOffsetTons * roundedPricePerTon : 0); return (