chore: add credits when subscription renewal and lifetime payment

This commit is contained in:
javayhu 2025-07-12 17:27:35 +08:00
parent b5997ded4c
commit b4e8585929
4 changed files with 75 additions and 47 deletions

View File

@ -167,7 +167,6 @@ TURNSTILE_SECRET_KEY=""
# https://mksaas.com/docs/jobs#setup
# -----------------------------------------------------------------------------
INNGEST_SIGNING_KEY=""
INNGEST_EVENT_KEY=""
# -----------------------------------------------------------------------------
# AI

View File

@ -120,7 +120,7 @@ export const websiteConfig: WebsiteConfig = {
credits: {
enable: true,
amount: 1000,
expireDays: 90,
expireDays: 30,
},
},
lifetime: {
@ -139,7 +139,7 @@ export const websiteConfig: WebsiteConfig = {
credits: {
enable: true,
amount: 2000,
expireDays: 120,
expireDays: 30,
},
},
},
@ -169,7 +169,7 @@ export const websiteConfig: WebsiteConfig = {
id: 'standard',
popular: true,
credits: 200,
expireDays: 60,
expireDays: 30,
price: {
priceId: process.env.NEXT_PUBLIC_STRIPE_PRICE_CREDITS_STANDARD!,
amount: 1490,
@ -181,7 +181,7 @@ export const websiteConfig: WebsiteConfig = {
id: 'premium',
popular: false,
credits: 500,
expireDays: 90,
expireDays: 30,
price: {
priceId: process.env.NEXT_PUBLIC_STRIPE_PRICE_CREDITS_PREMIUM!,
amount: 3990,
@ -193,7 +193,7 @@ export const websiteConfig: WebsiteConfig = {
id: 'enterprise',
popular: false,
credits: 1000,
expireDays: 120,
expireDays: 30,
price: {
priceId: process.env.NEXT_PUBLIC_STRIPE_PRICE_CREDITS_ENTERPRISE!,
amount: 6990,

View File

@ -354,45 +354,6 @@ export async function processExpiredCredits(userId: string) {
}
}
/**
* Add subscription renewal credits
* @param userId - User ID
* @param priceId - Price ID
*/
export async function addSubscriptionRenewalCredits(
userId: string,
priceId: string
) {
const pricePlan = findPlanByPriceId(priceId);
if (
!pricePlan ||
pricePlan.isFree ||
!pricePlan.credits ||
!pricePlan.credits.enable
) {
console.log(
`addSubscriptionRenewalCredits, no credits configured for plan ${priceId}`
);
return;
}
const credits = pricePlan.credits.amount;
const expireDays = pricePlan.credits.expireDays;
const now = new Date();
await addCredits({
userId,
amount: credits,
type: CREDIT_TRANSACTION_TYPE.SUBSCRIPTION_RENEWAL,
description: `Subscription renewal credits: ${credits} for ${now.getFullYear()}-${now.getMonth() + 1}`,
expireDays,
});
console.log(
`addSubscriptionRenewalCredits, ${credits} credits for user ${userId}, priceId: ${priceId}`
);
}
/**
* Add register gift credits
* @param userId - User ID
@ -492,6 +453,45 @@ export async function addMonthlyFreeCreditsIfNeed(userId: string) {
}
}
/**
* Add subscription renewal credits
* @param userId - User ID
* @param priceId - Price ID
*/
export async function addSubscriptionRenewalCredits(
userId: string,
priceId: string
) {
const pricePlan = findPlanByPriceId(priceId);
if (
!pricePlan ||
pricePlan.isFree ||
!pricePlan.credits ||
!pricePlan.credits.enable
) {
console.log(
`addSubscriptionRenewalCredits, no credits configured for plan ${priceId}`
);
return;
}
const credits = pricePlan.credits.amount;
const expireDays = pricePlan.credits.expireDays;
const now = new Date();
await addCredits({
userId,
amount: credits,
type: CREDIT_TRANSACTION_TYPE.SUBSCRIPTION_RENEWAL,
description: `Subscription renewal credits: ${credits} for ${now.getFullYear()}-${now.getMonth() + 1}`,
expireDays,
});
console.log(
`addSubscriptionRenewalCredits, ${credits} credits for user ${userId}, priceId: ${priceId}`
);
}
/**
* Add lifetime monthly credits
* @param userId - User ID

View File

@ -1,10 +1,19 @@
import { randomUUID } from 'crypto';
import { addCredits, addSubscriptionRenewalCredits } from '@/credits/credits';
import { websiteConfig } from '@/config/website';
import {
addCredits,
addLifetimeMonthlyCreditsIfNeed,
addSubscriptionRenewalCredits,
} from '@/credits/credits';
import { getCreditPackageById } from '@/credits/server';
import { CREDIT_TRANSACTION_TYPE } from '@/credits/types';
import { getDb } from '@/db';
import { payment, user } from '@/db/schema';
import { findPlanByPlanId, findPriceInPlan } from '@/lib/price-plan';
import {
findPlanByPlanId,
findPlanByPriceId,
findPriceInPlan,
} from '@/lib/price-plan';
import { sendNotification } from '@/notification/notification';
import { desc, eq } from 'drizzle-orm';
import { Stripe } from 'stripe';
@ -580,6 +589,15 @@ export class StripeProvider implements PaymentProvider {
`<< No payment record created for Stripe subscription ${stripeSubscription.id}`
);
}
// Conditionally handle credits after subscription creation
if (websiteConfig.credits?.enableCredits) {
// Add subscription renewal credits if plan config enables credits
const pricePlan = findPlanByPriceId(priceId);
if (pricePlan?.credits?.enable) {
await addSubscriptionRenewalCredits(userId, priceId);
}
}
}
/**
@ -771,6 +789,17 @@ export class StripeProvider implements PaymentProvider {
`<< Created one-time payment record for user ${userId}, price: ${priceId}`
);
// Conditionally handle credits after one-time payment
if (websiteConfig.credits?.enableCredits) {
// If the plan is lifetime and credits are enabled, add lifetime monthly credits if needed
const lifetimePlan = Object.values(
websiteConfig.price?.plans || {}
).find((plan) => plan.isLifetime && plan.credits?.enable);
if (lifetimePlan?.prices?.some((p) => p.priceId === priceId)) {
await addLifetimeMonthlyCreditsIfNeed(userId);
}
}
// Send notification
const amount = session.amount_total ? session.amount_total / 100 : 0;
await sendNotification(session.id, customerId, userId, amount);