Fix pricing discrepancy: use rounded-up price in Stripe checkout
All checks were successful
Build and Push Docker Images / docker (push) Successful in 48s

## 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 <noreply@anthropic.com>
This commit is contained in:
Matt 2025-10-30 14:17:14 +01:00
parent deb4351e21
commit e8d47f0fb3
2 changed files with 9 additions and 6 deletions

View File

@ -204,7 +204,8 @@ export function MobileOffsetOrder({ tons, monetaryAmount, onBack }: Props) {
const renderPortfolioPrice = (portfolio: Portfolio) => { const renderPortfolioPrice = (portfolio: Portfolio) => {
try { 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); return formatCurrency(pricePerTon, currencies.USD);
} catch (err) { } catch (err) {
console.error('Error formatting portfolio price:', 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) => { const handleInputChange = (field: keyof typeof formData, value: string) => {
setFormData(prev => ({ ...prev, [field]: value })); setFormData(prev => ({ ...prev, [field]: value }));

View File

@ -167,7 +167,7 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
const checkoutSession = await createCheckoutSession({ const checkoutSession = await createCheckoutSession({
tons: actualOffsetTons, tons: actualOffsetTons,
portfolioId: portfolio.id, 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); 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); return formatCurrency(pricePerTon, currencies.USD);
} catch (err) { } catch (err) {
console.error('Error formatting portfolio price:', 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 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 ( return (
<motion.div <motion.div