diff options
| author | Frank <[email protected]> | 2026-04-18 16:26:58 -0400 |
|---|---|---|
| committer | Frank <[email protected]> | 2026-04-18 17:33:28 -0400 |
| commit | 9d012b062186ef9900cc2673b77c446d38ebd789 (patch) | |
| tree | 0185f564ac585be5e50e1ba090da8a461e6fb4fc /packages/console/core/src | |
| parent | fbb0a93e12740c7fb3f5f7ff62eee027c157e351 (diff) | |
| download | opencode-9d012b062186ef9900cc2673b77c446d38ebd789.tar.gz opencode-9d012b062186ef9900cc2673b77c446d38ebd789.zip | |
zen: redeem credit
Diffstat (limited to 'packages/console/core/src')
| -rw-r--r-- | packages/console/core/src/billing.ts | 33 | ||||
| -rw-r--r-- | packages/console/core/src/schema/billing.sql.ts | 24 |
2 files changed, 54 insertions, 3 deletions
diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts index 9de413e60..d96b19ad7 100644 --- a/packages/console/core/src/billing.ts +++ b/packages/console/core/src/billing.ts @@ -1,6 +1,14 @@ import { Stripe } from "stripe" -import { Database, eq, sql } from "./drizzle" -import { BillingTable, LiteTable, PaymentTable, SubscriptionTable, UsageTable } from "./schema/billing.sql" +import { and, Database, eq, sql } from "./drizzle" +import { + BillingTable, + CouponTable, + CouponType, + LiteTable, + PaymentTable, + SubscriptionTable, + UsageTable, +} from "./schema/billing.sql" import { Actor } from "./actor" import { fn } from "./util/fn" import { z } from "zod" @@ -147,6 +155,27 @@ export namespace Billing { return amountInMicroCents } + export const redeemCoupon = async (email: string, type: (typeof CouponType)[number]) => { + const coupon = await Database.use((tx) => + tx + .select() + .from(CouponTable) + .where(and(eq(CouponTable.email, email), eq(CouponTable.type, type))) + .then((rows) => rows[0]), + ) + if (!coupon) throw new Error("Invalid coupon code") + if (coupon.timeRedeemed) throw new Error("Coupon already redeemed") + + if (type === "BUILDATHON") await grantCredit(Actor.workspace(), 500) + + await Database.use((tx) => + tx + .update(CouponTable) + .set({ timeRedeemed: sql`now()` }) + .where(and(eq(CouponTable.email, email), eq(CouponTable.type, type))), + ) + } + export const setMonthlyLimit = fn(z.number(), async (input) => { return await Database.use((tx) => tx diff --git a/packages/console/core/src/schema/billing.sql.ts b/packages/console/core/src/schema/billing.sql.ts index b06ca8966..f8dcbd2b1 100644 --- a/packages/console/core/src/schema/billing.sql.ts +++ b/packages/console/core/src/schema/billing.sql.ts @@ -1,4 +1,15 @@ -import { bigint, boolean, index, int, json, mysqlEnum, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core" +import { + bigint, + boolean, + index, + int, + json, + mysqlEnum, + mysqlTable, + primaryKey, + uniqueIndex, + varchar, +} from "drizzle-orm/mysql-core" import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types" import { workspaceIndexes } from "./workspace.sql" @@ -121,3 +132,14 @@ export const UsageTable = mysqlTable( }, (table) => [...workspaceIndexes(table), index("usage_time_created").on(table.workspaceID, table.timeCreated)], ) + +export const CouponType = ["BUILDATHON", "GOFREEMONTH"] as const +export const CouponTable = mysqlTable( + "coupon", + { + email: varchar("email", { length: 255 }), + type: mysqlEnum("type", CouponType).notNull(), + timeRedeemed: utc("time_redeemed"), + }, + (table) => [primaryKey({ columns: [table.email, table.type] })], +) |
