Shipping Delivery - VittorioDeMarzi/hero-beans GitHub Wiki

Shipping & Delivery

  • for now, we only deliver in Berlin and we have standard prices
  • we are planning to expand Germany-wide
  • we are planning to implement DHL API, but for now we have decided to mock delivery
  • to plan ahead, we use postal code detection to check if shipment fee is Berlin wide or Germany wide
  • Order should contain: status, shippedAt, deliveredAt
  • status: pending, paid, processing, shipped, in_transit, shipped

Fees

  • ≤ 2 kg | €5.90
  • 2-5 kg | €6.90
  • free shipping > 60€ total

How to Add Shipping Fees in Stripe

  • Calculates items_total + shipping_fee
  • sends to PaymentIntent

Where to Show Shipping Cost

  • Cart page → show estimated shipping before checkout.
    • Cart() { fun calculateShippingFee() }
  • Checkout page → final shipping fee after address is entered.
    • Order() { fun calculateShippingFee() }
  • Order confirmation → OrderConfirmationResponse:
    • Coffee subtotal
    • Shipping fee
    • Total
data class Address(
    val street: String,
    val postalCode: String,
    val city: String,
    val countryCode: String
)

fun isBerlin(address: Address): Boolean {
    return address.city.equals("Berlin", ignoreCase = true) ||
           address.postalCode.startsWith("10") ||  // Berlin postcodes start with 10xxx or 12xxx
           address.postalCode.startsWith("12")
}

fun calculateTotalAmount(itemTotalCents: Long, address: Address): Long {
    val berlinFee = 300L   // €3.00
    val germanyFee = 590L  // €5.90

    val shippingFee = if (isBerlin(address)) berlinFee else germanyFee
    return itemTotalCents + shippingFee
}

// to mock the shipping of Order
fun updateShippingStatuses() {
    val now = Instant.now()
    
    for (order in orders) {
        val daysSinceShip = Duration.between(order.shippedAt, now).toDays()
        
        order.status = when {
            daysSinceShip >= 2 -> {
                order.deliveredAt = now
                "delivered"
            }
            daysSinceShip >= 1 -> "in_transit"
            else -> "shipped"
        }
        
        println("Order ${order.id} is now '${order.status}'")
    }
}