import { jsonError, jsonOk, readJsonBody } from "@/lib/server/api"; import { requireSuperAdminUser } from "@/lib/server/auth/current-user"; import { getPlatformOrganization } from "@/lib/server/account-store"; import { postOrganizationTopUp } from "@/lib/server/billing-service"; import { postWalletEntry } from "@/lib/server/billing-store"; import { createId } from "@/lib/server/ids"; export const runtime = "nodejs"; export async function POST(request: Request) { try { const operator = await requireSuperAdminUser(); const body = await readJsonBody>(request); const organizationId = requiredString(body.organizationId, "组织"); const organization = await getPlatformOrganization(organizationId); if (!organization) throw badRequest("组织不存在。"); const amountFen = parseAmountFen(body.amountFen, body.amountYuan); if (amountFen <= 0) throw badRequest("请输入大于 0 的金额。"); const direction = body.direction === "debit" ? "debit" : body.direction === "credit" ? "credit" : null; if (!direction) throw badRequest("余额变动方向无效。"); const note = requiredString(body.note, "备注"); const amountLabel = (amountFen / 100).toFixed(2); const idempotencyKey = `manual-adjustment:${createId("entry")}`; const metadata = { operation: direction === "credit" ? "admin_top_up" : "manual_adjustment", direction, note, operatorId: operator.id, amountYuan: amountLabel }; const result = direction === "credit" ? await postOrganizationTopUp({ organizationId, amountFen, idempotencyKey, description: `管理员上账 · ${note}`, metadata }) : await postWalletEntry({ organizationId, kind: "adjustment", deltaFen: -amountFen, idempotencyKey, description: `管理员扣减 · ${note}`, metadata }); return jsonOk({ wallet: result.wallet, entry: result.entry }); } catch (error) { return jsonError(error, 500, { request, source: "api.admin.billing.adjustments" }); } } function parseAmountFen(amountFen: unknown, amountYuan: unknown): number { const fen = Number(amountFen); if (Number.isFinite(fen) && fen > 0) return Math.round(fen); const yuan = Number(amountYuan); if (!Number.isFinite(yuan) || yuan <= 0) return 0; return Math.round(yuan * 100); } function requiredString(value: unknown, label: string): string { const normalized = optionalString(value); if (!normalized) throw badRequest(`${label}不能为空。`); return normalized; } function optionalString(value: unknown): string | undefined { return typeof value === "string" && value.trim() ? value.trim() : undefined; } function badRequest(message: string): Error & { status: number } { return Object.assign(new Error(message), { status: 400 }); }