0

Update credit_billing.ts

This commit is contained in:
Nicolas 2024-06-05 13:22:03 -07:00
parent 5991000d2b
commit ec10eb09f3

View File

@ -36,7 +36,10 @@ export async function supaBillTeam(team_id: string, credits: number) {
let couponCredits = 0; let couponCredits = 0;
if (coupons && coupons.length > 0) { if (coupons && coupons.length > 0) {
couponCredits = coupons.reduce((total, coupon) => total + coupon.credits, 0); couponCredits = coupons.reduce(
(total, coupon) => total + coupon.credits,
0
);
} }
let sortedCoupons = coupons.sort((a, b) => b.credits - a.credits); let sortedCoupons = coupons.sort((a, b) => b.credits - a.credits);
@ -55,28 +58,27 @@ export async function supaBillTeam(team_id: string, credits: number) {
usedCredits = usedCredits - sortedCoupons[0].credits; usedCredits = usedCredits - sortedCoupons[0].credits;
// update coupon credits // update coupon credits
await supabase_service await supabase_service
.from("coupons") .from("coupons")
.update({ .update({
credits: 0 credits: 0,
}) })
.eq("id", sortedCoupons[0].id); .eq("id", sortedCoupons[0].id);
sortedCoupons.shift(); sortedCoupons.shift();
} else { } else {
// update coupon credits // update coupon credits
await supabase_service await supabase_service
.from("coupons") .from("coupons")
.update({ .update({
credits: sortedCoupons[0].credits - usedCredits credits: sortedCoupons[0].credits - usedCredits,
}) })
.eq("id", sortedCoupons[0].id); .eq("id", sortedCoupons[0].id);
usedCredits = 0; usedCredits = 0;
} }
} }
return await createCreditUsage({ team_id, credits: 0 }); return await createCreditUsage({ team_id, credits: 0 });
// not enough coupon credits and no subscription // not enough coupon credits and no subscription
} else { } else {
// update coupon credits // update coupon credits
const usedCredits = credits - couponCredits; const usedCredits = credits - couponCredits;
@ -84,7 +86,7 @@ export async function supaBillTeam(team_id: string, credits: number) {
await supabase_service await supabase_service
.from("coupons") .from("coupons")
.update({ .update({
credits: 0 credits: 0,
}) })
.eq("id", sortedCoupons[i].id); .eq("id", sortedCoupons[i].id);
} }
@ -92,7 +94,7 @@ export async function supaBillTeam(team_id: string, credits: number) {
return await createCreditUsage({ team_id, credits: usedCredits }); return await createCreditUsage({ team_id, credits: usedCredits });
} }
} }
// with subscription // with subscription
// using coupon + subscription credits: // using coupon + subscription credits:
if (credits > couponCredits) { if (credits > couponCredits) {
@ -101,14 +103,18 @@ export async function supaBillTeam(team_id: string, credits: number) {
await supabase_service await supabase_service
.from("coupons") .from("coupons")
.update({ .update({
credits: 0 credits: 0,
}) })
.eq("id", sortedCoupons[i].id); .eq("id", sortedCoupons[i].id);
} }
const usedCredits = credits - couponCredits; const usedCredits = credits - couponCredits;
return await createCreditUsage({ team_id, subscription_id: subscription.id, credits: usedCredits }); return await createCreditUsage({
team_id,
} else { // using only coupon credits subscription_id: subscription.id,
credits: usedCredits,
});
} else {
// using only coupon credits
let usedCredits = credits; let usedCredits = credits;
while (usedCredits > 0) { while (usedCredits > 0) {
// update coupons // update coupons
@ -116,26 +122,29 @@ export async function supaBillTeam(team_id: string, credits: number) {
usedCredits = usedCredits - sortedCoupons[0].credits; usedCredits = usedCredits - sortedCoupons[0].credits;
// update coupon credits // update coupon credits
await supabase_service await supabase_service
.from("coupons") .from("coupons")
.update({ .update({
credits: 0 credits: 0,
}) })
.eq("id", sortedCoupons[0].id); .eq("id", sortedCoupons[0].id);
sortedCoupons.shift(); sortedCoupons.shift();
} else { } else {
// update coupon credits // update coupon credits
await supabase_service await supabase_service
.from("coupons") .from("coupons")
.update({ .update({
credits: sortedCoupons[0].credits - usedCredits credits: sortedCoupons[0].credits - usedCredits,
}) })
.eq("id", sortedCoupons[0].id); .eq("id", sortedCoupons[0].id);
usedCredits = 0; usedCredits = 0;
} }
} }
return await createCreditUsage({ team_id, subscription_id: subscription.id, credits: 0 }); return await createCreditUsage({
team_id,
subscription_id: subscription.id,
credits: 0,
});
} }
} }
@ -144,7 +153,11 @@ export async function supaBillTeam(team_id: string, credits: number) {
return await createCreditUsage({ team_id, credits }); return await createCreditUsage({ team_id, credits });
} }
return await createCreditUsage({ team_id, subscription_id: subscription.id, credits }); return await createCreditUsage({
team_id,
subscription_id: subscription.id,
credits,
});
} }
export async function checkTeamCredits(team_id: string, credits: number) { export async function checkTeamCredits(team_id: string, credits: number) {
@ -157,12 +170,13 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
} }
// Retrieve the team's active subscription // Retrieve the team's active subscription
const { data: subscription, error: subscriptionError } = await supabase_service const { data: subscription, error: subscriptionError } =
.from("subscriptions") await supabase_service
.select("id, price_id, current_period_start, current_period_end") .from("subscriptions")
.eq("team_id", team_id) .select("id, price_id, current_period_start, current_period_end")
.eq("status", "active") .eq("team_id", team_id)
.single(); .eq("status", "active")
.single();
// Check for available coupons // Check for available coupons
const { data: coupons } = await supabase_service const { data: coupons } = await supabase_service
@ -173,7 +187,10 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
let couponCredits = 0; let couponCredits = 0;
if (coupons && coupons.length > 0) { if (coupons && coupons.length > 0) {
couponCredits = coupons.reduce((total, coupon) => total + coupon.credits, 0); couponCredits = coupons.reduce(
(total, coupon) => total + coupon.credits,
0
);
} }
// Free credits, no coupons // Free credits, no coupons
@ -182,7 +199,7 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
if (couponCredits >= credits) { if (couponCredits >= credits) {
return { success: true, message: "Sufficient credits available" }; return { success: true, message: "Sufficient credits available" };
} }
const { data: creditUsages, error: creditUsageError } = const { data: creditUsages, error: creditUsageError } =
await supabase_service await supabase_service
.from("credit_usage") .from("credit_usage")
@ -204,23 +221,30 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
console.log("totalCreditsUsed", totalCreditsUsed); console.log("totalCreditsUsed", totalCreditsUsed);
const end = new Date(); const end = new Date();
end.setDate(end.getDate() + 30); end.setDate(end.getDate() + 30);
// check if usage is within 80% of the limit // check if usage is within 80% of the limit
const creditLimit = FREE_CREDITS; const creditLimit = FREE_CREDITS;
const creditUsagePercentage = (totalCreditsUsed + credits) / creditLimit; const creditUsagePercentage = (totalCreditsUsed + credits) / creditLimit;
if (creditUsagePercentage >= 0.8) { if (creditUsagePercentage >= 0.8) {
await sendNotification(team_id, NotificationType.APPROACHING_LIMIT, new Date().toISOString(), end.toISOString()); await sendNotification(
team_id,
NotificationType.APPROACHING_LIMIT,
new Date().toISOString(),
end.toISOString()
);
} }
// 5. Compare the total credits used with the credits allowed by the plan. // 5. Compare the total credits used with the credits allowed by the plan.
if (totalCreditsUsed + credits > FREE_CREDITS) { if (totalCreditsUsed + credits > FREE_CREDITS) {
// Send email notification for insufficient credits // Send email notification for insufficient credits
await sendNotification(team_id, NotificationType.LIMIT_REACHED, new Date().toISOString(), end.toISOString()); await sendNotification(
team_id,
NotificationType.LIMIT_REACHED,
new Date().toISOString(),
end.toISOString()
);
return { return {
success: false, success: false,
message: "Insufficient credits, please upgrade!", message: "Insufficient credits, please upgrade!",
@ -231,19 +255,19 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
let totalCreditsUsed = 0; let totalCreditsUsed = 0;
try { try {
const { data: creditUsages, error: creditUsageError } = await supabase_service const { data: creditUsages, error: creditUsageError } =
.rpc("get_credit_usage_2", { await supabase_service.rpc("get_credit_usage_2", {
sub_id: subscription.id, sub_id: subscription.id,
start_time: subscription.current_period_start, start_time: subscription.current_period_start,
end_time: subscription.current_period_end end_time: subscription.current_period_end,
}); });
if (creditUsageError) { if (creditUsageError) {
console.error("Error calculating credit usage:", creditUsageError); console.error("Error calculating credit usage:", creditUsageError);
} }
if (creditUsages && creditUsages.length > 0) { if (creditUsages && creditUsages.length > 0) {
totalCreditsUsed = creditUsages[0].total_credits_used; totalCreditsUsed = creditUsages[0].total_credits_used;
} }
} catch (error) { } catch (error) {
console.error("Error calculating credit usage:", error); console.error("Error calculating credit usage:", error);
@ -260,7 +284,9 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
.single(); .single();
if (priceError) { if (priceError) {
throw new Error(`Failed to retrieve price for price_id: ${subscription.price_id}`); throw new Error(
`Failed to retrieve price for price_id: ${subscription.price_id}`
);
} }
const creditLimit = price.credits; const creditLimit = price.credits;
@ -268,11 +294,21 @@ export async function supaCheckTeamCredits(team_id: string, credits: number) {
// Compare the adjusted total credits used with the credits allowed by the plan // Compare the adjusted total credits used with the credits allowed by the plan
if (adjustedCreditsUsed + credits > price.credits) { if (adjustedCreditsUsed + credits > price.credits) {
await sendNotification(team_id, NotificationType.LIMIT_REACHED, subscription.current_period_start, subscription.current_period_end); await sendNotification(
team_id,
NotificationType.LIMIT_REACHED,
subscription.current_period_start,
subscription.current_period_end
);
return { success: false, message: "Insufficient credits, please upgrade!" }; return { success: false, message: "Insufficient credits, please upgrade!" };
} else if (creditUsagePercentage >= 0.8) { } else if (creditUsagePercentage >= 0.8) {
// Send email notification for approaching credit limit // Send email notification for approaching credit limit
await sendNotification(team_id, NotificationType.APPROACHING_LIMIT, subscription.current_period_start, subscription.current_period_end); await sendNotification(
team_id,
NotificationType.APPROACHING_LIMIT,
subscription.current_period_start,
subscription.current_period_end
);
} }
return { success: true, message: "Sufficient credits available" }; return { success: true, message: "Sufficient credits available" };
@ -298,7 +334,10 @@ export async function countCreditsAndRemainingForCurrentBillingPeriod(
let couponCredits = 0; let couponCredits = 0;
if (coupons && coupons.length > 0) { if (coupons && coupons.length > 0) {
couponCredits = coupons.reduce((total, coupon) => total + coupon.credits, 0); couponCredits = coupons.reduce(
(total, coupon) => total + coupon.credits,
0
);
} }
if (subscriptionError || !subscription) { if (subscriptionError || !subscription) {
@ -311,7 +350,9 @@ export async function countCreditsAndRemainingForCurrentBillingPeriod(
.eq("team_id", team_id); .eq("team_id", team_id);
if (creditUsageError || !creditUsages) { if (creditUsageError || !creditUsages) {
throw new Error(`Failed to retrieve credit usage for team_id: ${team_id}`); throw new Error(
`Failed to retrieve credit usage for team_id: ${team_id}`
);
} }
const totalCreditsUsed = creditUsages.reduce( const totalCreditsUsed = creditUsages.reduce(
@ -320,7 +361,11 @@ export async function countCreditsAndRemainingForCurrentBillingPeriod(
); );
const remainingCredits = FREE_CREDITS + couponCredits - totalCreditsUsed; const remainingCredits = FREE_CREDITS + couponCredits - totalCreditsUsed;
return { totalCreditsUsed: totalCreditsUsed, remainingCredits, totalCredits: FREE_CREDITS + couponCredits }; return {
totalCreditsUsed: totalCreditsUsed,
remainingCredits,
totalCredits: FREE_CREDITS + couponCredits,
};
} }
const { data: creditUsages, error: creditUsageError } = await supabase_service const { data: creditUsages, error: creditUsageError } = await supabase_service
@ -331,10 +376,15 @@ export async function countCreditsAndRemainingForCurrentBillingPeriod(
.lte("created_at", subscription.current_period_end); .lte("created_at", subscription.current_period_end);
if (creditUsageError || !creditUsages) { if (creditUsageError || !creditUsages) {
throw new Error(`Failed to retrieve credit usage for subscription_id: ${subscription.id}`); throw new Error(
`Failed to retrieve credit usage for subscription_id: ${subscription.id}`
);
} }
const totalCreditsUsed = creditUsages.reduce((acc, usage) => acc + usage.credits_used, 0); const totalCreditsUsed = creditUsages.reduce(
(acc, usage) => acc + usage.credits_used,
0
);
const { data: price, error: priceError } = await supabase_service const { data: price, error: priceError } = await supabase_service
.from("prices") .from("prices")
@ -343,7 +393,9 @@ export async function countCreditsAndRemainingForCurrentBillingPeriod(
.single(); .single();
if (priceError || !price) { if (priceError || !price) {
throw new Error(`Failed to retrieve price for price_id: ${subscription.price_id}`); throw new Error(
`Failed to retrieve price for price_id: ${subscription.price_id}`
);
} }
const remainingCredits = price.credits + couponCredits - totalCreditsUsed; const remainingCredits = price.credits + couponCredits - totalCreditsUsed;
@ -351,11 +403,19 @@ export async function countCreditsAndRemainingForCurrentBillingPeriod(
return { return {
totalCreditsUsed, totalCreditsUsed,
remainingCredits, remainingCredits,
totalCredits: price.credits totalCredits: price.credits,
}; };
} }
async function createCreditUsage({ team_id, subscription_id, credits }: { team_id: string, subscription_id?: string, credits: number }) { async function createCreditUsage({
team_id,
subscription_id,
credits,
}: {
team_id: string;
subscription_id?: string;
credits: number;
}) {
const { data: credit_usage } = await supabase_service const { data: credit_usage } = await supabase_service
.from("credit_usage") .from("credit_usage")
.insert([ .insert([
@ -369,4 +429,4 @@ async function createCreditUsage({ team_id, subscription_id, credits }: { team_i
.select(); .select();
return { success: true, credit_usage }; return { success: true, credit_usage };
} }