summaryrefslogtreecommitdiffhomepage
path: root/packages/console/app/src
diff options
context:
space:
mode:
authorFrank <[email protected]>2026-01-24 08:33:47 -0500
committerFrank <[email protected]>2026-01-24 11:48:19 -0500
commitd8bbb6df60dafd5f872ff418c2826ff8382c3749 (patch)
treeb9857a66c263ff442e8d62b05ebe7b6b58e9dbeb /packages/console/app/src
parent7c2e59de684104d3b436c4d4fbb2dd2426dcbd16 (diff)
downloadopencode-d8bbb6df60dafd5f872ff418c2826ff8382c3749.tar.gz
opencode-d8bbb6df60dafd5f872ff418c2826ff8382c3749.zip
zen: disable reload when reload fails
Diffstat (limited to 'packages/console/app/src')
-rw-r--r--packages/console/app/src/routes/stripe/webhook.ts70
1 files changed, 66 insertions, 4 deletions
diff --git a/packages/console/app/src/routes/stripe/webhook.ts b/packages/console/app/src/routes/stripe/webhook.ts
index 34f83b446..9e310dc07 100644
--- a/packages/console/app/src/routes/stripe/webhook.ts
+++ b/packages/console/app/src/routes/stripe/webhook.ts
@@ -141,8 +141,6 @@ export async function POST(input: APIEvent) {
return couponID
})()
- // get user
-
await Actor.provide("system", { workspaceID }, async () => {
// look up current billing
const billing = await Billing.get()
@@ -422,8 +420,8 @@ export async function POST(input: APIEvent) {
}
if (body.type === "invoice.payment_succeeded") {
if (
- body.data.object.billing_reason === "subscription_cycle" ||
- body.data.object.billing_reason === "subscription_create"
+ body.data.object.billing_reason === "subscription_create" ||
+ body.data.object.billing_reason === "subscription_cycle"
) {
const invoiceID = body.data.object.id as string
const amountInCents = body.data.object.amount_paid
@@ -476,6 +474,70 @@ export async function POST(input: APIEvent) {
},
}),
)
+ } else if (body.data.object.billing_reason === "manual") {
+ const workspaceID = body.data.object.metadata?.workspaceID
+ const amountInCents = body.data.object.metadata?.amount && parseInt(body.data.object.metadata?.amount)
+ const invoiceID = body.data.object.id as string
+ const customerID = body.data.object.customer as string
+
+ if (!workspaceID) throw new Error("Workspace ID not found")
+ if (!customerID) throw new Error("Customer ID not found")
+ if (!amountInCents) throw new Error("Amount not found")
+ if (!invoiceID) throw new Error("Invoice ID not found")
+
+ await Actor.provide("system", { workspaceID }, async () => {
+ // get payment id from invoice
+ const invoice = await Billing.stripe().invoices.retrieve(invoiceID, {
+ expand: ["payments"],
+ })
+ await Database.transaction(async (tx) => {
+ await tx
+ .update(BillingTable)
+ .set({
+ balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`,
+ reloadError: null,
+ timeReloadError: null,
+ })
+ .where(eq(BillingTable.workspaceID, Actor.workspace()))
+ await tx.insert(PaymentTable).values({
+ workspaceID: Actor.workspace(),
+ id: Identifier.create("payment"),
+ amount: centsToMicroCents(amountInCents),
+ invoiceID,
+ paymentID: invoice.payments?.data[0].payment.payment_intent as string,
+ customerID,
+ })
+ })
+ })
+ }
+ }
+ if (body.type === "invoice.payment_failed" || body.type === "invoice.payment_action_required") {
+ if (body.data.object.billing_reason === "manual") {
+ const workspaceID = body.data.object.metadata?.workspaceID
+ const invoiceID = body.data.object.id
+
+ if (!workspaceID) throw new Error("Workspace ID not found")
+ if (!invoiceID) throw new Error("Invoice ID not found")
+
+ const paymentIntent = await Billing.stripe().paymentIntents.retrieve(invoiceID);
+ console.log(JSON.stringify(paymentIntent))
+ const errorMessage =
+ typeof paymentIntent === "object" && paymentIntent !== null
+ ? paymentIntent.last_payment_error?.message
+ : undefined
+
+ await Actor.provide("system", { workspaceID }, async () => {
+ await Database.use((tx) =>
+ tx
+ .update(BillingTable)
+ .set({
+ reload: false,
+ reloadError: errorMessage ?? "Payment failed.",
+ timeReloadError: sql`now()`,
+ })
+ .where(eq(BillingTable.workspaceID, Actor.workspace())),
+ )
+ })
}
}
if (body.type === "charge.refunded") {