A flat shipping rate applied to every order regardless of weight, destination, or carrier method is a CWE-682 (Incorrect Calculation) defect that costs money in both directions: the store eats losses on heavy or long-distance shipments, or overcharges customers on lightweight local orders — which triggers chargebacks and cart abandonment. ISO 25010:2011 functional correctness requires that computed outputs match business rules. When every order is charged the same $5.00 regardless of a 50 lb appliance vs. a greeting card, the store is either subsidizing shipping losses or alienating customers who see inflated charges and leave.
Critical because a flat-rate-for-all calculation directly produces financial losses on heavy shipments or overcharges that drive customer disputes and abandonment.
Implement dynamic shipping calculation in lib/shipping.ts that uses at least 2 of 4 factors — weight, destination zone, method, or carrier API:
// lib/shipping.ts
async function calculateShippingCost(
items: OrderItem[],
destination: Address,
method: ShippingMethod
): Promise<number> {
const totalWeight = items.reduce((sum, item) => sum + item.weight * item.quantity, 0)
if (method === 'carrier') {
const shipment = await easypost.shipment.create({
from_address: { city: ORIGIN_CITY, state: ORIGIN_STATE },
to_address: { city: destination.city, state: destination.state },
parcel: { weight: totalWeight },
})
return Number(shipment.rates[0].rate) * 100 // convert to cents
}
const base = getBaseRate(destination.state)
const weightSurcharge = Math.ceil(totalWeight / 5) * 50 // 50¢ per 5 lbs
return base + weightSurcharge
}
Delete any hardcoded constant returned from a calculateShipping function and replace with this parameterised implementation.
ID: ecommerce-shipping-tax.shipping-calc.rate-calculation-accuracy
Severity: critical
What to look for: Enumerate all shipping rate calculation functions. For each, classify which factors are used: (1) product weight, (2) destination distance/zone, (3) selected shipping method, (4) carrier API integration. Count the number of factors considered. Report: X of 4 factors used.
Pass criteria: A shipping calculation function exists that applies rates based on at least 2 of 4 factors (weight, distance/zone, method selection, or carrier API). Rates are dynamically computed from order data, not hardcoded as a single flat rate for all orders.
Fail criteria: No shipping calculation logic exists, or all orders use a single hardcoded flat rate regardless of weight, destination, or method. Do not pass when a function named calculateShipping exists but returns a constant value.
Skip (N/A) when: Search package.json dependencies and all route/lib directories for shipping-related terms. If the store sells only digital products with no physical shipping, or shipping is fully managed by a third-party service with no in-house logic, skip.
Detail on fail: "Shipping calculation uses 0 of 4 factors. All orders charged flat $5.00 regardless of weight or destination." or "Weight-based function found but excludes items over 50 lbs — only 1 of 4 factors considered."
Cross-reference: Related to ecommerce-shipping-tax.shipping-calc.recalc-on-address-change (recalculation requires dynamic rates) and ecommerce-shipping-tax.checkout-integration.shipping-preview (displayed rate must match calculation).
Remediation: Implement dynamic shipping calculation in lib/shipping.ts based on order characteristics:
// lib/shipping.ts
async function calculateShippingCost(items: OrderItem[], destination: Address, method: ShippingMethod): Promise<number> {
const totalWeight = items.reduce((sum, item) => sum + item.weight * item.quantity, 0)
// Option 1: Integration with shipping API
if (method === 'carrier') {
const shipment = await easypost.shipment.create({
from_address: { city: 'origin_city' },
to_address: { city: destination.city, state: destination.state },
parcel: { weight: totalWeight }
})
return shipment.rates[0].rate // in cents
}
// Option 2: Weight-based lookup table
const baseCost = getBaseShippingRate(destination.state)
const weightFactor = Math.ceil(totalWeight / 5) * 0.5 // $0.50 per 5 lbs
return (baseCost + weightFactor) * 100 // convert to cents
}