feat(billing): implement robust in-app subscription cancellation & fix CI/CD socket port typo
This commit is contained in:
66
memento-note/lib/billing/cancel-subscription.ts
Normal file
66
memento-note/lib/billing/cancel-subscription.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
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,
|
||||
});
|
||||
|
||||
// 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',
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user