forked from coracle/caravel
Differentiate checkout id/session id
This commit is contained in:
@@ -98,6 +98,7 @@ CREATE TABLE IF NOT EXISTS intent (
|
|||||||
CREATE TABLE IF NOT EXISTS checkout (
|
CREATE TABLE IF NOT EXISTS checkout (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
invoice_id TEXT NOT NULL,
|
invoice_id TEXT NOT NULL,
|
||||||
|
session_id TEXT NOT NULL,
|
||||||
url TEXT NOT NULL,
|
url TEXT NOT NULL,
|
||||||
created_at INTEGER NOT NULL,
|
created_at INTEGER NOT NULL,
|
||||||
expires_at INTEGER NOT NULL,
|
expires_at INTEGER NOT NULL,
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ impl Billing {
|
|||||||
&& checkout.settled_at.is_none()
|
&& checkout.settled_at.is_none()
|
||||||
&& self
|
&& self
|
||||||
.stripe
|
.stripe
|
||||||
.is_checkout_paid(&checkout.id)
|
.is_checkout_paid(&checkout.session_id)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
@@ -534,7 +534,7 @@ impl Billing {
|
|||||||
/// transaction, so it's excluded here and not needlessly expired.
|
/// transaction, so it's excluded here and not needlessly expired.
|
||||||
async fn cleanup_pending_payments(&self, invoice: &Invoice) -> Result<()> {
|
async fn cleanup_pending_payments(&self, invoice: &Invoice) -> Result<()> {
|
||||||
for checkout in query::list_pending_checkouts_for_invoice(&invoice.id).await? {
|
for checkout in query::list_pending_checkouts_for_invoice(&invoice.id).await? {
|
||||||
if let Err(error) = self.stripe.expire_checkout_session(&checkout.id).await {
|
if let Err(error) = self.stripe.expire_checkout_session(&checkout.session_id).await {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
invoice = %invoice.id,
|
invoice = %invoice.id,
|
||||||
checkout = %checkout.id,
|
checkout = %checkout.id,
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ pub async fn settle_invoice_via_intent(
|
|||||||
/// Atomically record an invoice paid via a hosted Checkout session: stamp the
|
/// Atomically record an invoice paid via a hosted Checkout session: stamp the
|
||||||
/// checkout settled, clear the tenant's stored Stripe error, and mark the invoice
|
/// checkout settled, clear the tenant's stored Stripe error, and mark the invoice
|
||||||
/// paid. The checkout was inserted unsettled by [`insert_checkout`]. `checkout_id`
|
/// paid. The checkout was inserted unsettled by [`insert_checkout`]. `checkout_id`
|
||||||
/// is the Stripe Checkout Session id, which is the checkout's primary key.
|
/// is our row id, not the Stripe Checkout Session id.
|
||||||
pub async fn settle_invoice_via_checkout(
|
pub async fn settle_invoice_via_checkout(
|
||||||
tenant_pubkey: &str,
|
tenant_pubkey: &str,
|
||||||
checkout_id: &str,
|
checkout_id: &str,
|
||||||
@@ -491,23 +491,24 @@ pub async fn insert_bolt11(
|
|||||||
// --- Checkout records ---
|
// --- Checkout records ---
|
||||||
|
|
||||||
/// Record a pending Stripe Checkout session for an invoice, returning the stored
|
/// Record a pending Stripe Checkout session for an invoice, returning the stored
|
||||||
/// [`Checkout`]. Mirrors [`insert_bolt11`]: created unsettled, then stamped by
|
/// [`Checkout`]. Mirrors [`insert_bolt11`]: created unsettled with our own id,
|
||||||
/// [`settle_invoice_via_checkout`] once the session is paid. Keyed by the Stripe
|
/// then stamped by [`settle_invoice_via_checkout`] once the session is paid.
|
||||||
/// Checkout Session id, the same way `intent` is keyed by its PaymentIntent id.
|
|
||||||
pub async fn insert_checkout(
|
pub async fn insert_checkout(
|
||||||
invoice_id: &str,
|
invoice_id: &str,
|
||||||
session_id: &str,
|
session_id: &str,
|
||||||
url: &str,
|
url: &str,
|
||||||
expires_at: i64,
|
expires_at: i64,
|
||||||
) -> Result<Option<Checkout>> {
|
) -> Result<Option<Checkout>> {
|
||||||
|
let id = uuid::Uuid::new_v4().to_string();
|
||||||
let created_at = chrono::Utc::now().timestamp();
|
let created_at = chrono::Utc::now().timestamp();
|
||||||
|
|
||||||
Ok(sqlx::query_as::<_, Checkout>(
|
Ok(sqlx::query_as::<_, Checkout>(
|
||||||
"INSERT INTO checkout (id, invoice_id, url, created_at, expires_at)
|
"INSERT INTO checkout (id, invoice_id, session_id, url, created_at, expires_at)
|
||||||
VALUES (?, ?, ?, ?, ?) RETURNING *",
|
VALUES (?, ?, ?, ?, ?, ?) RETURNING *",
|
||||||
)
|
)
|
||||||
.bind(session_id)
|
.bind(id)
|
||||||
.bind(invoice_id)
|
.bind(invoice_id)
|
||||||
|
.bind(session_id)
|
||||||
.bind(url)
|
.bind(url)
|
||||||
.bind(created_at)
|
.bind(created_at)
|
||||||
.bind(expires_at)
|
.bind(expires_at)
|
||||||
|
|||||||
@@ -173,13 +173,14 @@ pub struct Bolt11 {
|
|||||||
|
|
||||||
/// A hosted Stripe Checkout session opened to pay an invoice on-session (so a 3D
|
/// A hosted Stripe Checkout session opened to pay an invoice on-session (so a 3D
|
||||||
/// Secure challenge can be cleared), shaped like [`Bolt11`]: created pending and
|
/// Secure challenge can be cleared), shaped like [`Bolt11`]: created pending and
|
||||||
/// stamped `settled_at` once paid. `id` is the Stripe Checkout Session id
|
/// stamped `settled_at` once paid. `id` is our uuid; `session_id` is the Stripe
|
||||||
/// (`cs_…`), used to reconcile and expire it; `url` is the hosted page we
|
/// Checkout Session (`cs_…`), used to reconcile and expire it; `url` is the
|
||||||
/// redirect the tenant to.
|
/// hosted page we redirect the tenant to.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
||||||
pub struct Checkout {
|
pub struct Checkout {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub invoice_id: String,
|
pub invoice_id: String,
|
||||||
|
pub session_id: String,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub created_at: i64,
|
pub created_at: i64,
|
||||||
pub expires_at: i64,
|
pub expires_at: i64,
|
||||||
|
|||||||
Reference in New Issue
Block a user