feat: Polar.sh payment integration, replace Shopier store approach
This commit is contained in:
@@ -11,7 +11,8 @@ import { DATABASE_ID, TABLES, type SubscriptionPayment, type TenantPlan } from "
|
||||
import { createAdminClient } from "./server";
|
||||
import { requireRole, requireTenant } from "./tenant-guard";
|
||||
import { PLAN_CATALOG } from "./subscription-types";
|
||||
import { isShopierEnabled } from "../payments/shopier";
|
||||
import { getShopierPlanUrl, isShopierEnabled } from "../payments/shopier";
|
||||
import { createPolarCheckout, isPolarEnabled } from "../payments/polar";
|
||||
|
||||
const PRO_VALIDITY_DAYS = 30;
|
||||
|
||||
@@ -227,6 +228,9 @@ export async function startShopierCheckoutAction(formData: FormData): Promise<vo
|
||||
const ctx = await requireTenant();
|
||||
requireRole(ctx, ["owner"]);
|
||||
|
||||
const storeUrl = getShopierPlanUrl(plan);
|
||||
if (!storeUrl) throw new Error("Shopier mağaza URL'i ayarlanmamış.");
|
||||
|
||||
const catalog = PLAN_CATALOG[plan];
|
||||
const orderId = generateOrderId();
|
||||
|
||||
@@ -244,6 +248,8 @@ export async function startShopierCheckoutAction(formData: FormData): Promise<vo
|
||||
currency: catalog.currency,
|
||||
status: "pending",
|
||||
provider: "shopier",
|
||||
// Webhook'ta tenant eşleştirmek için alıcı emailini sakla
|
||||
providerPayload: JSON.stringify({ userEmail: ctx.user.email }),
|
||||
},
|
||||
teamRowPermissions(ctx.tenantId),
|
||||
);
|
||||
@@ -257,14 +263,61 @@ export async function startShopierCheckoutAction(formData: FormData): Promise<vo
|
||||
changes: { plan, amount: catalog.price, provider: "shopier" },
|
||||
});
|
||||
|
||||
redirect(`/settings/billing/checkout/${orderId}/shopier`);
|
||||
// Kullanıcıyı doğrudan Shopier mağaza ürün sayfasına yönlendir
|
||||
redirect(storeUrl);
|
||||
}
|
||||
|
||||
// Unified entry point — branches on PAYMENT_PROVIDER env variable.
|
||||
// Set PAYMENT_PROVIDER=shopier in production; leave unset (or "mock") for testing.
|
||||
export async function startPolarCheckoutAction(formData: FormData): Promise<void> {
|
||||
const plan = String(formData.get("plan") ?? "") as TenantPlan;
|
||||
if (plan !== "pro") throw new Error("Geçersiz plan.");
|
||||
|
||||
const ctx = await requireTenant();
|
||||
requireRole(ctx, ["owner"]);
|
||||
|
||||
const catalog = PLAN_CATALOG[plan];
|
||||
const orderId = generateOrderId();
|
||||
const appUrl = process.env.APP_URL?.replace(/\/$/, "") ?? "http://localhost:3000";
|
||||
|
||||
const { tablesDB } = createAdminClient();
|
||||
await tablesDB.createRow(
|
||||
DATABASE_ID,
|
||||
TABLES.subscriptionPayments,
|
||||
ID.unique(),
|
||||
{
|
||||
tenantId: ctx.tenantId,
|
||||
createdBy: ctx.user.id,
|
||||
orderId,
|
||||
plan,
|
||||
amount: catalog.price,
|
||||
currency: catalog.currency,
|
||||
status: "pending",
|
||||
provider: "polar",
|
||||
},
|
||||
teamRowPermissions(ctx.tenantId),
|
||||
);
|
||||
|
||||
await logAudit({
|
||||
tenantId: ctx.tenantId,
|
||||
userId: ctx.user.id,
|
||||
action: "create",
|
||||
entityType: "subscription_payment",
|
||||
entityId: orderId,
|
||||
changes: { plan, amount: catalog.price, provider: "polar" },
|
||||
});
|
||||
|
||||
const checkout = await createPolarCheckout({
|
||||
orderId,
|
||||
tenantId: ctx.tenantId,
|
||||
userEmail: ctx.user.email,
|
||||
successUrl: `${appUrl}/settings/billing?upgraded=1`,
|
||||
});
|
||||
|
||||
redirect(checkout.url);
|
||||
}
|
||||
|
||||
// Unified entry point — PAYMENT_PROVIDER env ile yönlendirir.
|
||||
export async function startCheckoutAction(formData: FormData): Promise<void> {
|
||||
if (isShopierEnabled()) {
|
||||
return startShopierCheckoutAction(formData);
|
||||
}
|
||||
if (isPolarEnabled()) return startPolarCheckoutAction(formData);
|
||||
if (isShopierEnabled()) return startShopierCheckoutAction(formData);
|
||||
return startMockCheckoutAction(formData);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user