go: support coupon
parent
41612b3dbe
commit
01c5eb679c
|
|
@ -109,6 +109,12 @@ const zenLiteCouponFirstMonth50 = new stripe.Coupon("ZenLiteCouponFirstMonth50",
|
|||
appliesToProducts: [zenLiteProduct.id],
|
||||
duration: "once",
|
||||
})
|
||||
const zenLiteCouponFirstMonth100 = new stripe.Coupon("ZenLiteCouponFirstMonth100", {
|
||||
name: "First month 100% off",
|
||||
percentOff: 100,
|
||||
appliesToProducts: [zenLiteProduct.id],
|
||||
duration: "once",
|
||||
})
|
||||
const zenLitePrice = new stripe.Price("ZenLitePrice", {
|
||||
product: zenLiteProduct.id,
|
||||
currency: "usd",
|
||||
|
|
@ -124,6 +130,7 @@ const ZEN_LITE_PRICE = new sst.Linkable("ZEN_LITE_PRICE", {
|
|||
price: zenLitePrice.id,
|
||||
priceInr: 92900,
|
||||
firstMonth50Coupon: zenLiteCouponFirstMonth50.id,
|
||||
firstMonth100Coupon: zenLiteCouponFirstMonth100.id,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -229,6 +236,7 @@ new sst.cloudflare.x.SolidStart("Console", {
|
|||
SALESFORCE_INSTANCE_URL,
|
||||
ZEN_BLACK_PRICE,
|
||||
ZEN_LITE_PRICE,
|
||||
new sst.Secret("ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES"),
|
||||
new sst.Secret("ZEN_LIMITS"),
|
||||
new sst.Secret("ZEN_SESSION_SECRET"),
|
||||
...ZEN_MODELS,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import type { Stripe } from "stripe"
|
||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
||||
import type { APIEvent } from "@solidjs/start/server"
|
||||
import { and, Database, eq, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
||||
|
|
@ -111,27 +112,17 @@ export async function POST(input: APIEvent) {
|
|||
const customerID = body.data.object.customer as string
|
||||
const invoiceID = body.data.object.latest_invoice as string
|
||||
const subscriptionID = body.data.object.id as string
|
||||
const paymentMethodID = body.data.object.default_payment_method as string
|
||||
|
||||
if (!workspaceID) throw new Error("Workspace ID not found")
|
||||
if (!userID) throw new Error("User ID not found")
|
||||
if (!customerID) throw new Error("Customer ID not found")
|
||||
if (!invoiceID) throw new Error("Invoice ID not found")
|
||||
if (!subscriptionID) throw new Error("Subscription ID not found")
|
||||
|
||||
// get payment id from invoice
|
||||
const invoice = await Billing.stripe().invoices.retrieve(invoiceID, {
|
||||
expand: ["payments"],
|
||||
})
|
||||
const paymentID = invoice.payments?.data[0].payment.payment_intent as string
|
||||
if (!paymentID) throw new Error("Payment ID not found")
|
||||
if (!paymentMethodID) throw new Error("Payment method ID not found")
|
||||
|
||||
// get payment method for the payment intent
|
||||
const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, {
|
||||
expand: ["payment_method"],
|
||||
})
|
||||
const paymentMethod = paymentIntent.payment_method
|
||||
if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded")
|
||||
|
||||
const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID)
|
||||
await Actor.provide("system", { workspaceID }, async () => {
|
||||
// look up current billing
|
||||
const billing = await Billing.get()
|
||||
|
|
@ -200,26 +191,18 @@ export async function POST(input: APIEvent) {
|
|||
const amountInCents = body.data.object.amount_paid
|
||||
const customerID = body.data.object.customer as string
|
||||
const subscriptionID = body.data.object.parent?.subscription_details?.subscription as string
|
||||
const productID = body.data.object.lines?.data[0].pricing?.price_details?.product as string
|
||||
|
||||
if (!customerID) throw new Error("Customer ID not found")
|
||||
if (!invoiceID) throw new Error("Invoice ID not found")
|
||||
if (!subscriptionID) throw new Error("Subscription ID not found")
|
||||
|
||||
// get coupon id from subscription
|
||||
const subscriptionData = await Billing.stripe().subscriptions.retrieve(subscriptionID, {
|
||||
expand: ["discounts"],
|
||||
})
|
||||
const couponID =
|
||||
typeof subscriptionData.discounts[0] === "string"
|
||||
? subscriptionData.discounts[0]
|
||||
: subscriptionData.discounts[0]?.coupon?.id
|
||||
const productID = subscriptionData.items.data[0].price.product as string
|
||||
|
||||
// get payment id from invoice
|
||||
const invoice = await Billing.stripe().invoices.retrieve(invoiceID, {
|
||||
expand: ["payments"],
|
||||
expand: ["discounts", "payments"],
|
||||
})
|
||||
const paymentID = invoice.payments?.data[0].payment.payment_intent as string
|
||||
const paymentID = invoice.payments?.data[0]?.payment.payment_intent as string
|
||||
const couponID = (invoice.discounts[0] as Stripe.Discount).coupon?.id as string
|
||||
if (!paymentID) {
|
||||
// payment id can be undefined when using coupon
|
||||
if (!couponID) throw new Error("Payment ID not found")
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ export namespace Billing {
|
|||
const createSession = () =>
|
||||
Billing.stripe().checkout.sessions.create({
|
||||
mode: "subscription",
|
||||
discounts: [{ coupon: LiteData.firstMonth50Coupon() }],
|
||||
discounts: [{ coupon: LiteData.firstMonthCoupon(email!) }],
|
||||
...(billing.customerID
|
||||
? {
|
||||
customer: billing.customerID,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ export namespace LiteData {
|
|||
export const productID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.product)
|
||||
export const priceID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.price)
|
||||
export const priceInr = fn(z.void(), () => Resource.ZEN_LITE_PRICE.priceInr)
|
||||
export const firstMonth50Coupon = fn(z.void(), () => Resource.ZEN_LITE_PRICE.firstMonth50Coupon)
|
||||
export const firstMonthCoupon = fn(z.string(), (email) => {
|
||||
const invitees = Resource.ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES.value.split(",")
|
||||
return invitees.includes(email)
|
||||
? Resource.ZEN_LITE_PRICE.firstMonth100Coupon
|
||||
: Resource.ZEN_LITE_PRICE.firstMonth50Coupon
|
||||
})
|
||||
export const planName = fn(z.void(), () => "lite")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,12 @@ declare module "sst" {
|
|||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_PRICE": {
|
||||
"firstMonth100Coupon": string
|
||||
"firstMonth50Coupon": string
|
||||
"price": string
|
||||
"priceInr": number
|
||||
|
|
|
|||
|
|
@ -142,7 +142,12 @@ declare module "sst" {
|
|||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_PRICE": {
|
||||
"firstMonth100Coupon": string
|
||||
"firstMonth50Coupon": string
|
||||
"price": string
|
||||
"priceInr": number
|
||||
|
|
|
|||
|
|
@ -142,7 +142,12 @@ declare module "sst" {
|
|||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_PRICE": {
|
||||
"firstMonth100Coupon": string
|
||||
"firstMonth50Coupon": string
|
||||
"price": string
|
||||
"priceInr": number
|
||||
|
|
|
|||
|
|
@ -142,7 +142,12 @@ declare module "sst" {
|
|||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_PRICE": {
|
||||
"firstMonth100Coupon": string
|
||||
"firstMonth50Coupon": string
|
||||
"price": string
|
||||
"priceInr": number
|
||||
|
|
|
|||
|
|
@ -142,7 +142,12 @@ declare module "sst" {
|
|||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_PRICE": {
|
||||
"firstMonth100Coupon": string
|
||||
"firstMonth50Coupon": string
|
||||
"price": string
|
||||
"priceInr": number
|
||||
|
|
|
|||
|
|
@ -168,7 +168,12 @@ declare module "sst" {
|
|||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
}
|
||||
"ZEN_LITE_PRICE": {
|
||||
"firstMonth100Coupon": string
|
||||
"firstMonth50Coupon": string
|
||||
"price": string
|
||||
"priceInr": number
|
||||
|
|
|
|||
Loading…
Reference in New Issue