import assert from "node:assert/strict"; import { dbRun } from "../server/db.mjs"; const api = process.env.AI_DRAMA_API_BASE || "http://127.0.0.1:8787"; const scope = { "x-organization-id": "org-studio-lab", "x-workspace-id": "ws-local-aidrama", "x-project-id": "thunder-mouth" }; async function request(path, headers = {}, options = {}) { const response = await fetch(`${api}${path}`, { ...options, headers: { "content-type": "application/json", ...headers, ...(options.headers || {}) } }); const payload = await response.json().catch(() => ({})); return { response, payload }; } function assertOk(result, label) { assert.equal(result.response.ok, true, `${label}: ${result.response.status} ${result.payload.detail || result.payload.error || ""}`); return result.payload; } async function login(email) { const result = await request("/api/auth/login", {}, { method: "POST", body: JSON.stringify({ email, password: "Demo@123456" }) }); return { authorization: `Bearer ${assertOk(result, `${email} 登录`).session.token}` }; } const owner = { ...(await login("producer@local.test")), ...scope }; const writer = { ...(await login("writer@local.test")), ...scope }; const tierKey = `smoke-plan-${Date.now()}`; const planId = `plan-${tierKey}`; try { const before = assertOk(await request("/api/system/plan-templates", owner), "读取套餐模板"); assert.ok(before.planTemplates.length >= 3, "系统应至少有默认套餐模板"); const denied = await request("/api/system/plan-templates", writer, { method: "POST", body: JSON.stringify({ tierKey, name: "Writer Should Not Create Plan", seatLimit: 3, storageGb: 128, monthlyClipQuota: 200, limits: {}, features: {}, connectorPolicy: {} }) }); assert.equal(denied.response.status, 403, "非系统管理员不能创建系统套餐模板"); const created = assertOk(await request("/api/system/plan-templates", owner, { method: "POST", body: JSON.stringify({ tierKey, name: "Smoke Studio Plan", description: "烟测创建的本地商用套餐模板", billingCycle: "monthly", currency: "CNY", baseFee: 0, seatLimit: 6, storageGb: 384, monthlyClipQuota: 900, limits: { workspaces: 3, projects: 12, modelConnectors: 8, apiClients: 4 }, features: { batchGeneration: true, privateDeliveryPortal: true, comfyuiAdapter: false, externalCloudConnectors: false }, connectorPolicy: { allowedCostModes: ["local"], externalApprovalRequired: true }, supportSla: "烟测支持", status: "active" }) }), "创建套餐模板"); assert.equal(created.planTemplate.tierKey, tierKey, "创建后应返回新套餐"); assert.equal(created.planTemplate.seatLimit, 6, "席位上限未保存"); const updated = assertOk(await request(`/api/system/plan-templates/${encodeURIComponent(planId)}`, owner, { method: "PATCH", body: JSON.stringify({ ...created.planTemplate, seatLimit: 9, status: "archived" }) }), "更新并归档套餐模板"); assert.equal(updated.planTemplate.seatLimit, 9, "套餐模板更新未生效"); assert.equal(updated.planTemplate.status, "archived", "套餐模板归档未生效"); assert.ok(updated.planTemplates.some((plan) => plan.tierKey === tierKey && plan.status === "archived"), "系统模板列表应包含归档模板"); const commercial = assertOk(await request("/api/organizations/org-studio-lab/commercial", owner), "读取组织商业运营"); assert.equal(commercial.planTemplates.some((plan) => plan.tierKey === tierKey), false, "组织商业页不应把归档模板作为可分配模板"); console.log(`plan template smoke passed: ${api}`); } finally { dbRun("DELETE FROM audit_logs WHERE target_type = 'subscription_plan_template' AND target_id IN (?, ?)", [tierKey, planId]); dbRun("DELETE FROM subscription_plan_templates WHERE tier_key = ?", [tierKey]); }