handling if owner disconnects their stripe account
This commit is contained in:
@@ -338,6 +338,93 @@ class StripeWebhookService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle account.application.deauthorized webhook event.
|
||||
* Triggered when an owner disconnects their Stripe account from our platform.
|
||||
* @param {string} accountId - The connected account ID that was deauthorized
|
||||
* @returns {Object} - { processed, userId, pendingPayoutsCount, notificationSent }
|
||||
*/
|
||||
static async handleAccountDeauthorized(accountId) {
|
||||
logger.warn("Processing account.application.deauthorized webhook", {
|
||||
accountId,
|
||||
});
|
||||
|
||||
if (!accountId) {
|
||||
logger.warn("account.application.deauthorized webhook missing account ID");
|
||||
return { processed: false, reason: "missing_account_id" };
|
||||
}
|
||||
|
||||
try {
|
||||
// Find the user by their connected account ID
|
||||
const user = await User.findOne({
|
||||
where: { stripeConnectedAccountId: accountId },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
logger.warn("No user found for deauthorized Stripe account", { accountId });
|
||||
return { processed: false, reason: "user_not_found" };
|
||||
}
|
||||
|
||||
// Clear Stripe connection fields
|
||||
await user.update({
|
||||
stripeConnectedAccountId: null,
|
||||
stripePayoutsEnabled: false,
|
||||
});
|
||||
|
||||
logger.info("Cleared Stripe connection for deauthorized account", {
|
||||
userId: user.id,
|
||||
accountId,
|
||||
});
|
||||
|
||||
// Check for pending payouts that will now fail
|
||||
const pendingRentals = await Rental.findAll({
|
||||
where: {
|
||||
ownerId: user.id,
|
||||
payoutStatus: "pending",
|
||||
},
|
||||
});
|
||||
|
||||
if (pendingRentals.length > 0) {
|
||||
logger.warn("Owner disconnected account with pending payouts", {
|
||||
userId: user.id,
|
||||
pendingCount: pendingRentals.length,
|
||||
pendingRentalIds: pendingRentals.map((r) => r.id),
|
||||
});
|
||||
}
|
||||
|
||||
// Send notification email
|
||||
let notificationSent = false;
|
||||
try {
|
||||
await emailServices.payment.sendAccountDisconnectedEmail(user.email, {
|
||||
ownerName: user.firstName || user.name,
|
||||
hasPendingPayouts: pendingRentals.length > 0,
|
||||
pendingPayoutCount: pendingRentals.length,
|
||||
});
|
||||
notificationSent = true;
|
||||
logger.info("Sent account disconnected notification", { userId: user.id });
|
||||
} catch (emailError) {
|
||||
logger.error("Failed to send account disconnected notification", {
|
||||
userId: user.id,
|
||||
error: emailError.message,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
processed: true,
|
||||
userId: user.id,
|
||||
pendingPayoutsCount: pendingRentals.length,
|
||||
notificationSent,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("Error processing account.application.deauthorized webhook", {
|
||||
accountId,
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconcile payout statuses for an owner by checking Stripe for actual status.
|
||||
* This handles cases where payout.paid or payout.failed webhooks were missed.
|
||||
|
||||
Reference in New Issue
Block a user