Skip to content

Commit 54b3b3f

Browse files
committed
zen: redeem go
1 parent 9d012b0 commit 54b3b3f

11 files changed

Lines changed: 29 additions & 36 deletions

File tree

infra/console.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ new sst.cloudflare.x.SolidStart("Console", {
236236
SALESFORCE_INSTANCE_URL,
237237
ZEN_BLACK_PRICE,
238238
ZEN_LITE_PRICE,
239-
new sst.Secret("ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES"),
240239
new sst.Secret("ZEN_LIMITS"),
241240
new sst.Secret("ZEN_SESSION_SECRET"),
242241
...ZEN_MODELS,

packages/console/app/src/routes/stripe/webhook.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Actor } from "@opencode-ai/console-core/actor.js"
99
import { Resource } from "@opencode-ai/console-resource"
1010
import { LiteData } from "@opencode-ai/console-core/lite.js"
1111
import { BlackData } from "@opencode-ai/console-core/black.js"
12+
import { User } from "@opencode-ai/console-core/user.js"
1213

1314
export async function POST(input: APIEvent) {
1415
const body = await Billing.stripe().webhooks.constructEventAsync(
@@ -109,6 +110,8 @@ export async function POST(input: APIEvent) {
109110
if (type === "lite") {
110111
const workspaceID = body.data.object.metadata?.workspaceID
111112
const userID = body.data.object.metadata?.userID
113+
const userEmail = body.data.object.metadata?.userEmail
114+
const coupon = body.data.object.metadata?.coupon
112115
const customerID = body.data.object.customer as string
113116
const invoiceID = body.data.object.latest_invoice as string
114117
const subscriptionID = body.data.object.id as string
@@ -156,6 +159,10 @@ export async function POST(input: APIEvent) {
156159
id: Identifier.create("lite"),
157160
userID: userID,
158161
})
162+
163+
if (userEmail && coupon === LiteData.firstMonth100Coupon) {
164+
await Billing.redeemCoupon(userEmail, "GOFREEMONTH")
165+
}
159166
})
160167
})
161168
}

packages/console/app/src/routes/workspace/[id]/billing/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ export default function () {
2525
<Show when={billingInfo()?.customerID}>
2626
<ReloadSection />
2727
<MonthlyLimitSection />
28+
<RedeemSection />
2829
<PaymentSection />
2930
</Show>
30-
<RedeemSection />
3131
</Show>
3232
</div>
3333
</div>

packages/console/core/src/billing.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Stripe } from "stripe"
2-
import { and, Database, eq, sql } from "./drizzle"
2+
import { and, Database, eq, isNull, sql } from "./drizzle"
33
import {
44
BillingTable,
55
CouponTable,
@@ -176,6 +176,16 @@ export namespace Billing {
176176
)
177177
}
178178

179+
export const hasCoupon = async (email: string, type: (typeof CouponType)[number]) => {
180+
return await Database.use((tx) =>
181+
tx
182+
.select()
183+
.from(CouponTable)
184+
.where(and(eq(CouponTable.email, email), eq(CouponTable.type, type), isNull(CouponTable.timeRedeemed)))
185+
.then((rows) => rows.length > 0),
186+
)
187+
}
188+
179189
export const setMonthlyLimit = fn(z.number(), async (input) => {
180190
return await Database.use((tx) =>
181191
tx
@@ -274,16 +284,19 @@ export namespace Billing {
274284
const user = Actor.assert("user")
275285
const { successUrl, cancelUrl, method } = input
276286

277-
const email = await User.getAuthEmail(user.properties.userID)
287+
const email = (await User.getAuthEmail(user.properties.userID))!
278288
const billing = await Billing.get()
279289

280290
if (billing.subscriptionID) throw new Error("Already subscribed to Black")
281291
if (billing.liteSubscriptionID) throw new Error("Already subscribed to Lite")
282292

293+
const coupon = (await Billing.hasCoupon(email, "GOFREEMONTH"))
294+
? LiteData.firstMonth100Coupon
295+
: LiteData.firstMonth50Coupon
283296
const createSession = () =>
284297
Billing.stripe().checkout.sessions.create({
285298
mode: "subscription",
286-
discounts: [{ coupon: LiteData.firstMonthCoupon(email!) }],
299+
discounts: [{ coupon }],
287300
...(billing.customerID
288301
? {
289302
customer: billing.customerID,
@@ -293,7 +306,7 @@ export namespace Billing {
293306
},
294307
}
295308
: {
296-
customer_email: email!,
309+
customer_email: email,
297310
}),
298311
...(() => {
299312
if (method === "alipay") {
@@ -341,6 +354,8 @@ export namespace Billing {
341354
metadata: {
342355
workspaceID: Actor.workspace(),
343356
userID: user.properties.userID,
357+
userEmail: email,
358+
coupon,
344359
type: "lite",
345360
},
346361
},

packages/console/core/src/lite.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ export namespace LiteData {
1111
export const productID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.product)
1212
export const priceID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.price)
1313
export const priceInr = fn(z.void(), () => Resource.ZEN_LITE_PRICE.priceInr)
14-
export const firstMonthCoupon = fn(z.string(), (email) => {
15-
const invitees = Resource.ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES.value.split(",")
16-
return invitees.includes(email)
17-
? Resource.ZEN_LITE_PRICE.firstMonth100Coupon
18-
: Resource.ZEN_LITE_PRICE.firstMonth50Coupon
19-
})
14+
export const firstMonth100Coupon = Resource.ZEN_LITE_PRICE.firstMonth100Coupon
15+
export const firstMonth50Coupon = Resource.ZEN_LITE_PRICE.firstMonth50Coupon
2016
export const planName = fn(z.void(), () => "lite")
2117
}

packages/console/core/sst-env.d.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,6 @@ declare module "sst" {
142142
"type": "sst.sst.Secret"
143143
"value": string
144144
}
145-
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
146-
"type": "sst.sst.Secret"
147-
"value": string
148-
}
149145
"ZEN_LITE_PRICE": {
150146
"firstMonth100Coupon": string
151147
"firstMonth50Coupon": string

packages/console/function/sst-env.d.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,6 @@ declare module "sst" {
142142
"type": "sst.sst.Secret"
143143
"value": string
144144
}
145-
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
146-
"type": "sst.sst.Secret"
147-
"value": string
148-
}
149145
"ZEN_LITE_PRICE": {
150146
"firstMonth100Coupon": string
151147
"firstMonth50Coupon": string

packages/console/resource/sst-env.d.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,6 @@ declare module "sst" {
142142
"type": "sst.sst.Secret"
143143
"value": string
144144
}
145-
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
146-
"type": "sst.sst.Secret"
147-
"value": string
148-
}
149145
"ZEN_LITE_PRICE": {
150146
"firstMonth100Coupon": string
151147
"firstMonth50Coupon": string

packages/enterprise/sst-env.d.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,6 @@ declare module "sst" {
142142
"type": "sst.sst.Secret"
143143
"value": string
144144
}
145-
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
146-
"type": "sst.sst.Secret"
147-
"value": string
148-
}
149145
"ZEN_LITE_PRICE": {
150146
"firstMonth100Coupon": string
151147
"firstMonth50Coupon": string

packages/function/sst-env.d.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,6 @@ declare module "sst" {
142142
"type": "sst.sst.Secret"
143143
"value": string
144144
}
145-
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
146-
"type": "sst.sst.Secret"
147-
"value": string
148-
}
149145
"ZEN_LITE_PRICE": {
150146
"firstMonth100Coupon": string
151147
"firstMonth50Coupon": string

0 commit comments

Comments
 (0)