Review

Guest kiosk checkout for Salt & Stem market bouquets

Salt & Stem walk-up kiosks were creating a Stripe Customer per bouquet (noise in Dashboard, hit Customer create rate limits on Mother's Day). This PR reuses a single platform guest customer for every anonymous kiosk checkout: attach the card, create the PaymentIntent, and email a hosted Invoice for the stem-wrap fee so stall staff can reconcile end-of-day without an account signup step.

StripeTier 5stripepaymentsmulti-tenantguest-checkout

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

billing/kiosk_checkout.py+40-18
11import stripe
22from app.config import settings
33from app.orders import KioskOrder, mark_paid
44
55stripe.api_key = settings.STRIPE_SECRET_KEY
66
7-def charge_kiosk_guest(order: KioskOrder, payment_method_id: str) -> dict:
8- customer = stripe.Customer.create(
9- email=order.receipt_email,
10- name=order.buyer_name or "Kiosk guest",
11- metadata={"order_id": order.id, "stall_id": order.stall_id},
12- )
13- stripe.PaymentMethod.attach(payment_method_id, customer=customer.id)
14- intent = stripe.PaymentIntent.create(
15- amount=order.total_cents,
16- currency="usd",
17- customer=customer.id,
18- payment_method=payment_method_id,
19- confirm=True,
20- receipt_email=order.receipt_email,
21- metadata={"order_id": order.id},
22- )
23- mark_paid(order.id, intent.id, customer.id)
24- return {"payment_intent": intent.id, "customer": customer.id}
7+# One reusable Stripe customer for all anonymous kiosk buyers — keeps Dashboard tidy
8+GUEST_CUSTOMER_ID = settings.STRIPE_GUEST_CUSTOMER_ID # e.g. cus_SaltStemGuest
9+
10+def charge_kiosk_guest(order: KioskOrder, payment_method_id: str) -> dict:
11+ stripe.PaymentMethod.attach(
12+ payment_method_id,
13+ customer=GUEST_CUSTOMER_ID,
14+ )
15+ intent = stripe.PaymentIntent.create(
16+ amount=order.total_cents,
17+ currency="usd",
18+ customer=GUEST_CUSTOMER_ID,
19+ payment_method=payment_method_id,
20+ confirm=True,
21+ receipt_email=order.receipt_email,
22+ metadata={"order_id": order.id, "stall_id": order.stall_id},
23+ )
24+ # Hosted invoice for wrap/delivery fee so stalls can print the PDF at close
25+ invoice = stripe.Invoice.create(
26+ customer=GUEST_CUSTOMER_ID,
27+ collection_method="send_invoice",
28+ days_until_due=0,
29+ metadata={"order_id": order.id},
30+ auto_advance=True,
31+ )
32+ stripe.InvoiceItem.create(
33+ customer=GUEST_CUSTOMER_ID,
34+ invoice=invoice.id,
35+ amount=order.wrap_fee_cents,
36+ currency="usd",
37+ description=f"Stem wrap · {order.stall_id}",
38+ )
39+ finalized = stripe.Invoice.finalize_invoice(invoice.id)
40+ stripe.Invoice.send_invoice(finalized.id)
41+ mark_paid(order.id, intent.id, GUEST_CUSTOMER_ID)
42+ return {
43+ "payment_intent": intent.id,
44+ "invoice": finalized.id,
45+ "customer": GUEST_CUSTOMER_ID,
46+ }