Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions apps/labrinth/src/database/models/charge_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,7 @@ impl DBCharge {
.collect::<Result<Vec<_>, serde_json::Error>>()?)
}

/// Returns all charges which are missing a tax identifier, that is, are 1. succeeded, 2. have a tax amount and
/// 3. haven't been assigned a tax identifier yet.
/// Returns all charges which are missing a tax identifier, that is, are succeeded and haven't been assigned a tax identifier yet.
///
/// Charges are locked.
pub async fn get_missing_tax_identifier_lock(
Expand All @@ -349,7 +348,6 @@ impl DBCharge {
WHERE
status = 'succeeded'
AND tax_platform_id IS NULL
AND tax_amount <> 0
ORDER BY due ASC
FOR NO KEY UPDATE SKIP LOCKED
LIMIT $1
Expand Down
108 changes: 73 additions & 35 deletions apps/labrinth/src/queue/billing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,6 @@ pub async fn index_subscriptions(
let redis = redis_ref.clone();

async move {
let stripe_customer_id =
DBUser::get_id(charge.user_id, &pg, &redis)
.await?
.ok_or_else(|| {
ApiError::from(DatabaseError::Database(
sqlx::Error::RowNotFound,
))
})
.and_then(|user| {
user.stripe_customer_id.ok_or_else(|| {
ApiError::InvalidInput(
"User has no Stripe customer ID"
.to_owned(),
)
})
})?;

let tax_id = DBProductsTaxIdentifier::get_price(
charge.price_id,
&pg,
Expand All @@ -164,26 +147,81 @@ pub async fn index_subscriptions(
)
})?;

let Ok(customer_id): Result<stripe::CustomerId, _> =
stripe_customer_id.parse()
else {
return Err(ApiError::InvalidInput(
"Charge's Stripe customer ID was invalid"
.to_owned(),
));
};
let stripe_address = 'a: {
let stripe_id: stripe::PaymentIntentId = charge
.payment_platform_id
.as_ref()
.and_then(|x| x.parse().ok())
.ok_or_else(|| {
ApiError::InvalidInput(
"Charge has no payment platform ID"
.to_owned(),
)
})?;

let customer = stripe::Customer::retrieve(
&stripe_client,
&customer_id,
&[],
)
.await?;
// Attempt retrieving the address via the payment intent's payment method

let pi = stripe::PaymentIntent::retrieve(
&stripe_client,
&stripe_id,
&["payment_method"],
)
.await?;

let pi_stripe_address = pi
.payment_method
.and_then(|x| x.into_object())
.and_then(|x| x.billing_details.address);

match pi_stripe_address {
Some(address) => break 'a address,
None => {
warn!("PaymentMethod had no address");
}
};

let stripe_customer_id =
DBUser::get_id(charge.user_id, &pg, &redis)
.await?
.ok_or_else(|| {
ApiError::from(DatabaseError::Database(
sqlx::Error::RowNotFound,
))
})
.and_then(|user| {
user.stripe_customer_id.ok_or_else(
|| {
ApiError::InvalidInput(
"User has no Stripe customer ID"
.to_owned(),
)
},
)
})?;

let Ok(customer_id): Result<stripe::CustomerId, _> =
stripe_customer_id.parse()
else {
return Err(ApiError::InvalidInput(
"Charge's Stripe customer ID was invalid"
.to_owned(),
));
};

let customer = stripe::Customer::retrieve(
&stripe_client,
&customer_id,
&[],
)
.await?;

let Some(stripe_address) = customer.address else {
return Err(ApiError::InvalidInput(
"Stripe customer had no address".to_owned(),
));
};

let Some(stripe_address) = customer.address else {
return Err(ApiError::InvalidInput(
"Stripe customer had no address".to_owned(),
));
stripe_address
};

let customer_address =
Expand Down
17 changes: 15 additions & 2 deletions apps/labrinth/src/routes/internal/billing/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,15 +530,28 @@ pub async fn create_or_update_payment_intent(
}

if let Some(payment_intent_id) = existing_payment_intent {
let update_payment_intent = stripe::UpdatePaymentIntent {
let mut update_payment_intent = stripe::UpdatePaymentIntent {
amount: Some(charge_data.amount + tax_amount),
currency: Some(inferred_stripe_currency),
customer: Some(customer_id),
metadata: Some(metadata),
payment_method: Some(payment_method.id.clone()),
..Default::default()
};

// If the payment request type was done through a confirmation token,
// the payment method ID is an invalid placeholder so we don't want
// to use it.
//
// The PaymentIntent will be confirmed using the confirmation token
// by the client.
if let PaymentSession::Interactive {
payment_request_type: PaymentRequestType::PaymentMethod { .. },
} = &payment_session
{
update_payment_intent.payment_method =
Some(payment_method.id.clone());
}

stripe::PaymentIntent::update(
stripe_client,
&payment_intent_id,
Expand Down