core: let Go referral rewards lower active usage limits

This commit is contained in:
vimtor
2026-05-17 09:43:33 +02:00
parent 6056a51656
commit c60219e229
2 changed files with 42 additions and 35 deletions

View File

@@ -18,6 +18,7 @@ import { centsToMicroCents } from "./util/price"
import { User } from "./user"
import { BlackData } from "./black"
import { LiteData } from "./lite"
import { getMonthlyBounds, getWeekBounds } from "./util/date"
export namespace Billing {
export const ITEM_CREDIT_NAME = "opencode credits"
@@ -155,6 +156,45 @@ export namespace Billing {
return amountInMicroCents
}
export const subtractLiteUsage = async (workspaceID: string, amountInMicroCents: number) => {
await Database.transaction(async (tx) => {
const lite = await tx
.select({ timeCreated: LiteTable.timeCreated })
.from(LiteTable)
.where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted)))
.then((rows) => rows[0])
if (!lite) throw new Error("Subscribe to Go before applying referral rewards")
const now = new Date()
const week = getWeekBounds(now)
const month = getMonthlyBounds(now, lite.timeCreated)
const rollingWindowSeconds = LiteData.getLimits().rollingWindow * 3600
await tx
.update(LiteTable)
.set({
monthlyUsage: sql`
CASE
WHEN ${LiteTable.timeMonthlyUpdated} >= ${month.start} THEN GREATEST(0, COALESCE(${LiteTable.monthlyUsage}, 0) - ${amountInMicroCents})
ELSE ${LiteTable.monthlyUsage}
END
`,
weeklyUsage: sql`
CASE
WHEN ${LiteTable.timeWeeklyUpdated} >= ${week.start} THEN GREATEST(0, COALESCE(${LiteTable.weeklyUsage}, 0) - ${amountInMicroCents})
ELSE ${LiteTable.weeklyUsage}
END
`,
rollingUsage: sql`
CASE
WHEN UNIX_TIMESTAMP(${LiteTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN GREATEST(0, COALESCE(${LiteTable.rollingUsage}, 0) - ${amountInMicroCents})
ELSE ${LiteTable.rollingUsage}
END
`,
})
.where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted)))
})
}
export const redeemCoupon = async (email: string, type: (typeof CouponType)[number]) => {
const coupon = await Database.use((tx) =>
tx

View File

@@ -8,10 +8,9 @@ import { ReferralRewardTable, ReferralTable } from "./schema/referral.sql"
import { AuthTable } from "./schema/auth.sql"
import { UserTable } from "./schema/user.sql"
import { WorkspaceTable } from "./schema/workspace.sql"
import { LiteData } from "./lite"
import { centsToMicroCents, microCentsToCents } from "./util/price"
import { getMonthlyBounds, getWeekBounds } from "./util/date"
import { fn } from "./util/fn"
import { Billing } from "./billing"
export namespace Referral {
export const REWARD_AMOUNT = centsToMicroCents(500)
@@ -183,13 +182,6 @@ export namespace Referral {
if (!reward) throw new Error("Referral reward not found")
if (reward.timeApplied) return { applied: false }
const lite = await tx
.select({ id: LiteTable.id, timeCreated: LiteTable.timeCreated })
.from(LiteTable)
.where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted)))
.then((rows) => rows[0])
if (!lite) throw new Error("Subscribe to Go before applying referral rewards")
const update = await tx
.update(ReferralRewardTable)
.set({
@@ -205,32 +197,7 @@ export namespace Referral {
)
if (update.rowsAffected === 0) return { applied: false }
const week = getWeekBounds(new Date())
const month = getMonthlyBounds(new Date(), lite.timeCreated)
const rollingWindowSeconds = LiteData.getLimits().rollingWindow * 3600
await tx
.update(LiteTable)
.set({
monthlyUsage: sql`
CASE
WHEN ${LiteTable.timeMonthlyUpdated} >= ${month.start} THEN GREATEST(0, COALESCE(${LiteTable.monthlyUsage}, 0) - ${reward.amount})
ELSE ${LiteTable.monthlyUsage}
END
`,
weeklyUsage: sql`
CASE
WHEN ${LiteTable.timeWeeklyUpdated} >= ${week.start} THEN GREATEST(0, COALESCE(${LiteTable.weeklyUsage}, 0) - ${reward.amount})
ELSE ${LiteTable.weeklyUsage}
END
`,
rollingUsage: sql`
CASE
WHEN UNIX_TIMESTAMP(${LiteTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN GREATEST(0, COALESCE(${LiteTable.rollingUsage}, 0) - ${reward.amount})
ELSE ${LiteTable.rollingUsage}
END
`,
})
.where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted)))
await Billing.subtractLiteUsage(workspaceID, reward.amount)
return { applied: true, amount: microCentsToCents(reward.amount) }
})