Skip to content

Commit

Permalink
Preorder deposit separate from primary payment
Browse files Browse the repository at this point in the history
  • Loading branch information
Winston-Hsiao committed Nov 15, 2024
1 parent f900442 commit adc871b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 26 deletions.
15 changes: 12 additions & 3 deletions frontend/src/components/orders/OrderCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ const OrderCard: React.FC<{ orderWithProduct: OrderWithProduct }> = ({
const [isEditAddressModalOpen, setIsEditAddressModalOpen] = useState(false);
const [isCancelOrderModalOpen, setIsCancelOrderModalOpen] = useState(false);

const currentStatusIndex = orderStatuses.indexOf(order.status);
const currentStatusIndex =
order.status === "preorder_placed"
? -1
: orderStatuses.indexOf(order.status);
const isRedStatus = redStatuses.includes(order.status);
const showStatusBar = activeStatuses.includes(order.status);

Expand Down Expand Up @@ -90,10 +93,14 @@ const OrderCard: React.FC<{ orderWithProduct: OrderWithProduct }> = ({
</p>

{order.status === "preorder_placed" && order.preorder_deposit_amount && (
<div className="mb-4 p-3 bg-blue-50 text-blue-800 rounded-md">
<div className="mb-4 p-3 bg-gray-4 text-gray-12 rounded-md">
<p className="font-medium">
Pre-order Deposit: {formatPrice(order.preorder_deposit_amount)}
</p>
<p className="font-medium mt-1">
Amount Due:{" "}
{formatPrice(order.price_amount - order.preorder_deposit_amount)}
</p>
{order.preorder_release_date && (
<p className="text-sm mt-1">
Expected Release:{" "}
Expand Down Expand Up @@ -195,7 +202,9 @@ const OrderCard: React.FC<{ orderWithProduct: OrderWithProduct }> = ({
index <= currentStatusIndex
? getStatusColor(status)
: "bg-gray-300"
} ${index === 0 ? "rounded-l-full" : ""} ${index === 4 ? "rounded-r-full" : ""}`}
} ${index === 0 ? "rounded-l-full" : ""} ${
index === 4 ? "rounded-r-full" : ""
}`}
style={{
width: "20%",
float: "left",
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/lib/utils/formatString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export function capitalizeFirstLetter(string: string) {
// for order statuses
// e.g. "in_development" -> "In Development"
export const normalizeStatus = (status: string): string => {
if (status === "preorder_placed") {
return "Pre-order Placed";
}

return status
.split("_")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
Expand Down
9 changes: 6 additions & 3 deletions store/app/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,10 @@ class Order(StoreBaseModel):
currency: str
quantity: int
stripe_checkout_session_id: str
stripe_product_id: str
stripe_connect_account_id: str
stripe_customer_id: str | None = None
stripe_product_id: str
stripe_price_id: str
stripe_customer_id: str
stripe_payment_method_id: str | None = None
stripe_payment_intent_id: str | None = None
preorder_release_date: int | None = None
Expand Down Expand Up @@ -624,8 +625,9 @@ def create(
quantity: int,
stripe_checkout_session_id: str,
stripe_product_id: str,
stripe_price_id: str,
stripe_connect_account_id: str,
stripe_customer_id: str | None = None,
stripe_customer_id: str,
stripe_payment_method_id: str | None = None,
stripe_payment_intent_id: str | None = None,
preorder_release_date: int | None = None,
Expand Down Expand Up @@ -654,6 +656,7 @@ def create(
quantity=quantity,
stripe_checkout_session_id=stripe_checkout_session_id,
stripe_product_id=stripe_product_id,
stripe_price_id=stripe_price_id,
stripe_connect_account_id=stripe_connect_account_id,
stripe_customer_id=stripe_customer_id,
stripe_payment_method_id=stripe_payment_method_id,
Expand Down
56 changes: 36 additions & 20 deletions store/app/routers/stripe.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,27 +168,34 @@ async def stripe_connect_webhook(request: Request, crud: Crud = Depends(Crud.get

# Use the connected account ID when retrieving the session
try:
complete_session = stripe.checkout.Session.retrieve(session["id"], stripe_account=connected_account_id)
# Get the seller's connect account ID from metadata
seller_connect_account_id = session["metadata"].get("seller_connect_account_id")
if not seller_connect_account_id:
raise ValueError("Missing seller connect account ID")

# Retrieve the complete session with the seller's account
session = stripe.checkout.Session.retrieve(session["id"], stripe_account=seller_connect_account_id)

# Handle setup completion for preorders
if complete_session["mode"] == "setup":
if session["mode"] == "setup":
try:
seller_connect_account_id = complete_session["metadata"].get("seller_connect_account_id")
seller_connect_account_id = session["metadata"].get("seller_connect_account_id")
if not seller_connect_account_id:
raise ValueError("Missing seller connect account ID")

# Get the customer ID from the session
connected_customer_id = complete_session["customer"]
connected_customer_id = session["customer"]

# Check for existing payment method
existing_payment_method_id = complete_session["metadata"].get("existing_payment_method_id")
existing_payment_method_id = session["metadata"].get("existing_payment_method_id")

if existing_payment_method_id:
# Use existing payment method
payment_method_id = existing_payment_method_id
else:
# Retrieve SetupIntent with expanded payment method
setup_intent = stripe.SetupIntent.retrieve(
complete_session["setup_intent"],
session["setup_intent"],
expand=["payment_method"],
stripe_account=seller_connect_account_id,
)
Expand All @@ -214,23 +221,24 @@ async def stripe_connect_webhook(request: Request, crud: Crud = Depends(Crud.get

# Create order for preorder
order_data = {
"user_id": complete_session["client_reference_id"],
"user_email": complete_session["customer_details"]["email"],
"stripe_checkout_session_id": complete_session["id"],
"user_id": session["client_reference_id"],
"user_email": session["customer_details"]["email"],
"stripe_checkout_session_id": session["id"],
"stripe_payment_intent_id": None,
"amount": int(complete_session["metadata"]["price_amount"]),
"price_amount": int(session["metadata"]["price_amount"]),
"preorder_deposit_amount": int(session["metadata"]["deposit_amount"]),
"currency": "usd",
"status": "preorder_placed",
"quantity": 1,
"stripe_product_id": complete_session["metadata"].get("stripe_product_id"),
"stripe_product_id": session["metadata"].get("stripe_product_id"),
"stripe_customer_id": connected_customer_id,
"stripe_payment_method_id": payment_method_id,
"stripe_connect_account_id": seller_connect_account_id,
"preorder_release_date": complete_session["metadata"].get("preorder_release_date"),
"preorder_release_date": session["metadata"].get("preorder_release_date"),
}

# Add shipping details if available
if shipping_details := complete_session.get("shipping_details"):
if shipping_details := session.get("shipping_details"):
shipping_address = shipping_details.get("address", {})
order_data.update(
{
Expand All @@ -257,7 +265,7 @@ async def stripe_connect_webhook(request: Request, crud: Crud = Depends(Crud.get

else:
# Handle regular checkout completion with the complete session
await handle_checkout_session_completed(complete_session, crud)
await handle_checkout_session_completed(session, crud)
except Exception as e:
logger.error("Error retrieving complete session: %s", str(e))
raise
Expand Down Expand Up @@ -290,8 +298,15 @@ async def handle_checkout_session_completed(session: Dict[str, Any], crud: Crud)
session["payment_intent"], stripe_account=seller_connect_account_id
)

# Create the order
# Determine if this is a preorder and get the correct price amount
is_preorder = session["metadata"].get("is_preorder") == "true"
price_amount = (
int(session["metadata"].get("full_price_amount")) # Use full price for preorders
if is_preorder
else session["amount_total"] # Use session amount for regular orders
)

# Create the order
order_data = {
"user_id": session.get("client_reference_id"),
"user_email": session["customer_details"]["email"],
Expand All @@ -301,13 +316,13 @@ async def handle_checkout_session_completed(session: Dict[str, Any], crud: Crud)
"stripe_customer_id": session["customer"],
"stripe_payment_method_id": payment_intent.payment_method if payment_intent else None,
"stripe_payment_intent_id": session.get("payment_intent"),
"price_amount": session["amount_total"],
"price_amount": price_amount,
"currency": session["currency"],
"status": "preorder_placed" if is_preorder else "processing",
"quantity": quantity,
"preorder_deposit_amount": session["amount_total"] if is_preorder else None,
"preorder_deposit_amount": (session["amount_total"] if is_preorder else None),
"preorder_release_date": session["metadata"].get("preorder_release_date") if is_preorder else None,
"stripe_price_id": session["metadata"].get("full_price_id") if is_preorder else None,
"stripe_price_id": session["metadata"].get("stripe_price_id"),
"shipping_name": shipping_details.get("name"),
"shipping_address_line1": shipping_address.get("line1"),
"shipping_address_line2": shipping_address.get("line2"),
Expand Down Expand Up @@ -419,6 +434,7 @@ async def create_checkout_session(
"user_email": user.email,
"product_id": listing.stripe_product_id or "",
"listing_type": listing.inventory_type,
"seller_connect_account_id": seller.stripe_connect_account_id,
}

if existing_payment_methods:
Expand Down Expand Up @@ -456,15 +472,15 @@ async def create_checkout_session(
"setup_future_usage": "off_session", # Save card for future charge
"metadata": {
"is_preorder": "true",
"full_price_id": listing.stripe_price_id,
"stripe_price_id": listing.stripe_price_id,
"remaining_amount": str(listing.price_amount - listing.preorder_deposit_amount),
"listing_id": listing.id,
},
},
"metadata": {
**metadata,
"is_preorder": "true",
"full_price_id": listing.stripe_price_id,
"stripe_price_id": listing.stripe_price_id,
"full_price_amount": str(listing.price_amount),
},
}
Expand Down

0 comments on commit adc871b

Please sign in to comment.