Expose gateway billing flows from the synced server baseline
The preserved local work adds PopiNewAPI billing checkout, gateway account binding, and matching web console/pricing surfaces on top of the current test-server baseline. During the merge, the start-end video helpers from the deployed baseline were kept alongside the actionGenerate prompt handling from the WIP.
Constraint: Current usable baseline is 7054436, already deployed on the test server.
Rejected: Commit the WIP before syncing the baseline | would have hidden conflicts with the deployed start-end-frame changes.
Confidence: medium
Scope-risk: broad
Directive: Do not deploy this commit to the test server without rechecking gateway credentials and billing checkout behavior in that environment.
Tested: go test ./...
Tested: make build
Tested: cd web && npm run build
This commit is contained in:
@@ -29,6 +29,9 @@ export type AuthSessionView = {
|
||||
user: PopiartUser;
|
||||
session_key?: string;
|
||||
upstream_key_masked?: string;
|
||||
gateway_user_id?: number;
|
||||
gateway_access_token_masked?: string;
|
||||
gateway_bound: boolean;
|
||||
};
|
||||
|
||||
export type Skill = {
|
||||
@@ -84,6 +87,149 @@ export type BudgetUsage = {
|
||||
};
|
||||
};
|
||||
|
||||
export type Project = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type ProjectListResponse = {
|
||||
items: Project[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
};
|
||||
|
||||
export type BillingPlan = {
|
||||
id: string;
|
||||
product_type: string;
|
||||
badge: string;
|
||||
name: string;
|
||||
price: string;
|
||||
cadence: string;
|
||||
summary: string;
|
||||
features: string[];
|
||||
cta: string;
|
||||
highlight?: boolean;
|
||||
};
|
||||
|
||||
export type BillingCatalog = {
|
||||
plans: BillingPlan[];
|
||||
capabilities: {
|
||||
subscription_status: boolean;
|
||||
credit_balance: boolean;
|
||||
invoices: boolean;
|
||||
checkout: boolean;
|
||||
};
|
||||
source: string;
|
||||
note?: string;
|
||||
};
|
||||
|
||||
export type BillingSubscription = {
|
||||
billing_preference: string;
|
||||
subscriptions: Array<{
|
||||
subscription?: {
|
||||
id?: number;
|
||||
status?: string;
|
||||
amount_total?: number;
|
||||
amount_used?: number;
|
||||
start_time?: number;
|
||||
end_time?: number;
|
||||
next_reset_time?: number;
|
||||
member_level?: string;
|
||||
};
|
||||
}>;
|
||||
all_subscriptions: Array<Record<string, unknown>>;
|
||||
subscription_points: Record<
|
||||
string,
|
||||
{
|
||||
available_points?: number;
|
||||
total_points?: number;
|
||||
used_points?: number;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export type BillingCredits = {
|
||||
wallets: Array<{
|
||||
id: number;
|
||||
source_type: string;
|
||||
points: number;
|
||||
points_total: number;
|
||||
expire_at: number;
|
||||
status: string;
|
||||
priority: number;
|
||||
origin_currency: string;
|
||||
origin_amount: number;
|
||||
}>;
|
||||
balance: number;
|
||||
};
|
||||
|
||||
export type BillingSubscriptionPlan = {
|
||||
plan: {
|
||||
id: number;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
description: string;
|
||||
price_amount: number;
|
||||
currency: string;
|
||||
price_amount_cny?: number;
|
||||
price_amount_usd?: number;
|
||||
points_amount: number;
|
||||
duration_unit: string;
|
||||
duration_value: number;
|
||||
recommended?: boolean;
|
||||
member_level?: string;
|
||||
total_amount?: number;
|
||||
quota_reset_period?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type BillingSubscriptionPlans = {
|
||||
items: BillingSubscriptionPlan[];
|
||||
};
|
||||
|
||||
export type BillingPointsPackage = {
|
||||
id: number;
|
||||
name: string;
|
||||
currency: string;
|
||||
price_amount: number;
|
||||
points_amount: number;
|
||||
bonus_points: number;
|
||||
enabled: boolean;
|
||||
};
|
||||
|
||||
export type BillingPointsPackages = {
|
||||
items: BillingPointsPackage[];
|
||||
};
|
||||
|
||||
export type BillingCheckoutResult = {
|
||||
message?: string;
|
||||
trade_no?: string;
|
||||
url?: string;
|
||||
code_url?: string;
|
||||
data?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type BillingOrderPage = {
|
||||
page: number;
|
||||
page_size: number;
|
||||
total: number;
|
||||
items: Array<Record<string, unknown>>;
|
||||
};
|
||||
|
||||
export type BillingInvoices = {
|
||||
subscription_orders: BillingOrderPage;
|
||||
point_orders: BillingOrderPage;
|
||||
};
|
||||
|
||||
export type GatewayBindResponse = {
|
||||
gateway_user_id: number;
|
||||
gateway_username?: string;
|
||||
gateway_display_name?: string;
|
||||
gateway_email?: string;
|
||||
gateway_bound: boolean;
|
||||
};
|
||||
|
||||
export class PopiartApiError extends Error {
|
||||
status: number;
|
||||
code?: string;
|
||||
@@ -221,3 +367,70 @@ export async function getBudgetUsage() {
|
||||
}
|
||||
return popiartRequest<BudgetUsage>("/budget/usage", { token });
|
||||
}
|
||||
|
||||
export async function getProjects() {
|
||||
const token = await getSessionToken();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return popiartRequest<ProjectListResponse>("/projects", { token });
|
||||
}
|
||||
|
||||
export async function getBillingCatalog() {
|
||||
return popiartRequest<BillingCatalog>("/billing/catalog");
|
||||
}
|
||||
|
||||
export async function getBillingSubscription() {
|
||||
const token = await getSessionToken();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return popiartRequest<BillingSubscription>("/billing/subscription", { token });
|
||||
}
|
||||
|
||||
export async function getBillingCredits() {
|
||||
const token = await getSessionToken();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return popiartRequest<BillingCredits>("/billing/credits", { token });
|
||||
}
|
||||
|
||||
export async function getBillingSubscriptionPlans() {
|
||||
const token = await getSessionToken();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return popiartRequest<BillingSubscriptionPlans>("/billing/subscription/plans", { token });
|
||||
}
|
||||
|
||||
export async function getBillingPointsPackages() {
|
||||
const token = await getSessionToken();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return popiartRequest<BillingPointsPackages>("/billing/points/packages", { token });
|
||||
}
|
||||
|
||||
export async function getBillingInvoices(options?: {
|
||||
keyword?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}) {
|
||||
const token = await getSessionToken();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
const query = new URLSearchParams();
|
||||
if (options?.keyword) {
|
||||
query.set("keyword", options.keyword);
|
||||
}
|
||||
if (options?.page && options.page > 0) {
|
||||
query.set("p", String(options.page));
|
||||
}
|
||||
if (options?.pageSize && options.pageSize > 0) {
|
||||
query.set("page_size", String(options.pageSize));
|
||||
}
|
||||
const suffix = query.toString();
|
||||
return popiartRequest<BillingInvoices>(`/billing/invoices${suffix ? `?${suffix}` : ""}`, { token });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user