idempotency for stripe transfer, refund, charge
This commit is contained in:
@@ -104,12 +104,20 @@ class StripeService {
|
||||
metadata = {},
|
||||
}) {
|
||||
try {
|
||||
const transfer = await stripe.transfers.create({
|
||||
amount: Math.round(amount * 100), // Convert to cents
|
||||
currency,
|
||||
destination,
|
||||
metadata,
|
||||
});
|
||||
// Generate idempotency key from rental ID to prevent duplicate transfers
|
||||
const idempotencyKey = metadata?.rentalId
|
||||
? `transfer_rental_${metadata.rentalId}`
|
||||
: undefined;
|
||||
|
||||
const transfer = await stripe.transfers.create(
|
||||
{
|
||||
amount: Math.round(amount * 100), // Convert to cents
|
||||
currency,
|
||||
destination,
|
||||
metadata,
|
||||
},
|
||||
idempotencyKey ? { idempotencyKey } : undefined
|
||||
);
|
||||
|
||||
return transfer;
|
||||
} catch (error) {
|
||||
@@ -216,12 +224,20 @@ class StripeService {
|
||||
reason = "requested_by_customer",
|
||||
}) {
|
||||
try {
|
||||
const refund = await stripe.refunds.create({
|
||||
payment_intent: paymentIntentId,
|
||||
amount: Math.round(amount * 100), // Convert to cents
|
||||
metadata,
|
||||
reason,
|
||||
});
|
||||
// Generate idempotency key - include amount to allow multiple partial refunds
|
||||
const idempotencyKey = metadata?.rentalId
|
||||
? `refund_rental_${metadata.rentalId}_${Math.round(amount * 100)}`
|
||||
: undefined;
|
||||
|
||||
const refund = await stripe.refunds.create(
|
||||
{
|
||||
payment_intent: paymentIntentId,
|
||||
amount: Math.round(amount * 100), // Convert to cents
|
||||
metadata,
|
||||
reason,
|
||||
},
|
||||
idempotencyKey ? { idempotencyKey } : undefined
|
||||
);
|
||||
|
||||
return refund;
|
||||
} catch (error) {
|
||||
@@ -252,20 +268,28 @@ class StripeService {
|
||||
metadata = {}
|
||||
) {
|
||||
try {
|
||||
// Generate idempotency key to prevent duplicate charges for same rental
|
||||
const idempotencyKey = metadata?.rentalId
|
||||
? `charge_rental_${metadata.rentalId}`
|
||||
: undefined;
|
||||
|
||||
// Create a payment intent with the stored payment method
|
||||
const paymentIntent = await stripe.paymentIntents.create({
|
||||
amount: Math.round(amount * 100), // Convert to cents
|
||||
currency: "usd",
|
||||
payment_method: paymentMethodId,
|
||||
customer: customerId, // Include customer ID
|
||||
confirm: true, // Automatically confirm the payment
|
||||
off_session: true, // Indicate this is an off-session payment
|
||||
return_url: `${
|
||||
process.env.FRONTEND_URL || "http://localhost:3000"
|
||||
}/complete-payment`,
|
||||
metadata,
|
||||
expand: ["latest_charge.payment_method_details"], // Expand to get payment method details
|
||||
});
|
||||
const paymentIntent = await stripe.paymentIntents.create(
|
||||
{
|
||||
amount: Math.round(amount * 100), // Convert to cents
|
||||
currency: "usd",
|
||||
payment_method: paymentMethodId,
|
||||
customer: customerId, // Include customer ID
|
||||
confirm: true, // Automatically confirm the payment
|
||||
off_session: true, // Indicate this is an off-session payment
|
||||
return_url: `${
|
||||
process.env.FRONTEND_URL || "http://localhost:3000"
|
||||
}/complete-payment`,
|
||||
metadata,
|
||||
expand: ["latest_charge.payment_method_details"], // Expand to get payment method details
|
||||
},
|
||||
idempotencyKey ? { idempotencyKey } : undefined
|
||||
);
|
||||
|
||||
// Check if additional authentication is required
|
||||
if (paymentIntent.status === "requires_action") {
|
||||
|
||||
Reference in New Issue
Block a user