67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
import { prisma } from '@/lib/prisma';
|
|
import { stripe } from '@/lib/stripe';
|
|
|
|
export interface CancelSubscriptionResult {
|
|
success: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* Cancels an active user subscription by setting its auto-renew (cancel_at_period_end) status to true
|
|
* in Stripe and synchronizing the status back into the local Prisma database.
|
|
*
|
|
* @param userId - Unique identifier of the user
|
|
* @returns An object indicating the success or failure of the operation
|
|
*/
|
|
export async function cancelSubscription(userId: string): Promise<CancelSubscriptionResult> {
|
|
if (!userId) {
|
|
return { success: false, error: 'User ID is required' };
|
|
}
|
|
|
|
try {
|
|
const subscription = await prisma.subscription.findUnique({
|
|
where: { userId },
|
|
});
|
|
|
|
if (!subscription) {
|
|
return { success: false, error: 'No active subscription found' };
|
|
}
|
|
|
|
if (subscription.stripeSubscriptionId) {
|
|
// Direct call to Stripe API with period end cancellation set to true
|
|
const updatedSub = await stripe.subscriptions.update(subscription.stripeSubscriptionId, {
|
|
cancel_at_period_end: true,
|
|
}) as any;
|
|
|
|
// Local database synchronization
|
|
await prisma.subscription.update({
|
|
where: { userId },
|
|
data: {
|
|
cancelAtPeriodEnd: true,
|
|
canceledAt: updatedSub.canceled_at ? new Date(updatedSub.canceled_at * 1000) : new Date(),
|
|
currentPeriodEnd: updatedSub.current_period_end ? new Date(updatedSub.current_period_end * 1000) : subscription.currentPeriodEnd,
|
|
updatedAt: new Date(),
|
|
},
|
|
});
|
|
} else {
|
|
// Mock mode cancel (e.g. for development / local bypass testing)
|
|
await prisma.subscription.update({
|
|
where: { userId },
|
|
data: {
|
|
cancelAtPeriodEnd: true,
|
|
canceledAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
});
|
|
}
|
|
|
|
return { success: true };
|
|
} catch (error: any) {
|
|
console.error('[cancelSubscription] Error processing cancellation:', error);
|
|
return {
|
|
success: false,
|
|
error: error.message || 'Failed to cancel subscription',
|
|
};
|
|
}
|
|
}
|