add lifetime 1-4x
This commit is contained in:
@@ -239,10 +239,10 @@ export function computeApplyPlan(
|
||||
): AccountUpdate {
|
||||
const stack = (acc.plan_stack || []).slice();
|
||||
const newPlan = payment.plan;
|
||||
const newDays = payment.plan === "lifetime" ? null : (payment.months ?? 1) * 30;
|
||||
const newDays = payment.plan.startsWith("lifetime") ? null : (payment.months ?? 1) * 30;
|
||||
|
||||
const currentExpiry = acc.plan_expires_at ? new Date(acc.plan_expires_at) : null;
|
||||
const currentIsActive = acc.plan === "lifetime"
|
||||
const currentIsActive = acc.plan.startsWith("lifetime")
|
||||
|| (acc.plan !== "free" && currentExpiry && currentExpiry > now);
|
||||
|
||||
if (!currentIsActive || acc.plan === "free") {
|
||||
@@ -256,7 +256,7 @@ export function computeApplyPlan(
|
||||
}
|
||||
|
||||
if (planTier(newPlan) > planTier(acc.plan)) {
|
||||
const remainingDays = acc.plan === "lifetime"
|
||||
const remainingDays = acc.plan.startsWith("lifetime")
|
||||
? null
|
||||
: Math.ceil((currentExpiry!.getTime() - now.getTime()) / 86400000);
|
||||
const newStack = insertIntoStack(stack, { plan: acc.plan, remaining_days: remainingDays });
|
||||
|
||||
@@ -18,10 +18,10 @@ export async function generateReceipt(paymentId: number): Promise<string> {
|
||||
? new Date(payment.paid_at).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" })
|
||||
: "-";
|
||||
const createdDate = new Date(payment.created_at).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" });
|
||||
const planNames: Record<string, string> = { pro: "Pro", pro2x: "Pro 2x", pro4x: "Pro 4x", lifetime: "Lifetime" };
|
||||
const planNames: Record<string, string> = { pro: "Pro", pro2x: "Pro 2x", pro4x: "Pro 4x", lifetime: "Lifetime", lifetime2x: "Lifetime 2x", lifetime4x: "Lifetime 4x" };
|
||||
const planName = planNames[payment.plan] || payment.plan;
|
||||
const planLabel = payment.plan === "lifetime"
|
||||
? "Lifetime"
|
||||
const planLabel = payment.plan.startsWith("lifetime")
|
||||
? planName
|
||||
: `${planName} × ${payment.months} month${payment.months > 1 ? "s" : ""}`;
|
||||
|
||||
const txRows = txs.map((tx: any) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Elysia, t } from "elysia";
|
||||
import sql from "./db";
|
||||
import { derive } from "./address";
|
||||
import { getExchangeRates, getAvailableCoins, fetchQrBase64 } from "./freedom";
|
||||
import { PLAN_PRICING as PLANS, COINS } from "../../shared/plans";
|
||||
import { PLAN_PRICING as PLANS, COINS, planTier } from "../../shared/plans";
|
||||
import { generateReceipt } from "./receipt";
|
||||
import { watchPayment } from "./monitor";
|
||||
import { resolveKey as sharedResolveKey, extractAuthKey } from "../../shared/auth";
|
||||
@@ -45,11 +45,13 @@ export const routes = new Elysia()
|
||||
|
||||
const { plan, months, coin } = body;
|
||||
|
||||
if (plan === "lifetime") {
|
||||
if (plan.startsWith("lifetime")) {
|
||||
const [acc] = await sql`SELECT plan, plan_stack FROM accounts WHERE id = ${accountId}`;
|
||||
const stack = typeof acc.plan_stack === "string" ? JSON.parse(acc.plan_stack) : (acc.plan_stack || []);
|
||||
const hasLifetime = acc.plan === "lifetime" || stack.some((s: any) => s.plan === "lifetime");
|
||||
if (hasLifetime) { set.status = 400; return { error: "You already have a lifetime plan" }; }
|
||||
const buyingTier = planTier(plan);
|
||||
const ownedLifetimes = [acc.plan, ...stack.map((s: any) => s.plan)].filter((p: string) => p.startsWith("lifetime"));
|
||||
const maxOwnedTier = Math.max(0, ...ownedLifetimes.map((p: string) => planTier(p)));
|
||||
if (maxOwnedTier >= buyingTier) { set.status = 400; return { error: "You already have this lifetime tier or higher" }; }
|
||||
}
|
||||
|
||||
if (!COINS[coin]) { set.status = 400; return { error: `Unknown coin: ${coin}` }; }
|
||||
@@ -60,9 +62,9 @@ export const routes = new Elysia()
|
||||
if (!planDef) { set.status = 400; return { error: `Unknown plan: ${plan}` }; }
|
||||
let amountUsd = planDef.priceUsd ?? (planDef.monthlyUsd! * (months ?? 1));
|
||||
|
||||
if (plan === "lifetime" && planDef.priceUsd) {
|
||||
if (plan.startsWith("lifetime") && planDef.priceUsd) {
|
||||
const [{ total }] = await sql`SELECT COALESCE(SUM(amount_usd), 0)::numeric as total FROM payments WHERE account_id = ${accountId} AND status = 'paid'`;
|
||||
const credit = Math.min(Number(total), planDef.priceUsd * 0.75);
|
||||
const credit = Math.min(Number(total), planDef.priceUsd * 0.90);
|
||||
amountUsd = Math.max(amountUsd - credit, 1);
|
||||
}
|
||||
const rates = await getExchangeRates();
|
||||
@@ -87,7 +89,7 @@ export const routes = new Elysia()
|
||||
|
||||
const [payment] = await sql`
|
||||
INSERT INTO payments (account_id, plan, months, amount_usd, coin, amount_crypto, address, derivation_index, expires_at)
|
||||
VALUES (${accountId}, ${plan}, ${plan === "lifetime" ? null : months ?? 1}, ${amountUsd}, ${coin}, ${amountCrypto}, ${address}, ${next_index}, ${expiresAt.toISOString()})
|
||||
VALUES (${accountId}, ${plan}, ${plan.startsWith("lifetime") ? null : months ?? 1}, ${amountUsd}, ${coin}, ${amountCrypto}, ${address}, ${next_index}, ${expiresAt.toISOString()})
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user