363f9169ba
Expose margin multiplier, FX rate, and cost-mode settings under 计费中心 so operators can adjust DeepSeek billing without env edits. Co-authored-by: Cursor <cursoragent@cursor.com>
112 lines
3.2 KiB
JavaScript
112 lines
3.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { once } from 'node:events';
|
|
import test from 'node:test';
|
|
import { createAdminApp } from './app.mjs';
|
|
|
|
function createServices({ role = 'admin' } = {}) {
|
|
let stored = {
|
|
useBackendCost: true,
|
|
usdCnyRate: 7.2,
|
|
marginMultiplier: 1.2,
|
|
inputCentsPer1k: 2,
|
|
outputCentsPer1k: 6,
|
|
minBillCents: 1,
|
|
costEstimateFromTokens: true,
|
|
costEstimateInputUsdPer1M: 0.27,
|
|
costEstimateOutputUsdPer1M: 1.1,
|
|
};
|
|
|
|
return {
|
|
services: {
|
|
ready: Promise.resolve(),
|
|
parseCookies: () => ({ test_session: 'token' }),
|
|
USER_COOKIE: 'test_session',
|
|
userLoginCookies: () => [],
|
|
clearUserSessionCookie: () => {},
|
|
resolveCookieDomainForRequest: () => undefined,
|
|
userAuth: {
|
|
getMe: async () => ({ id: 'admin-id', username: 'admin', role }),
|
|
},
|
|
billingConfigService: {
|
|
getAdminConfig: async () => ({
|
|
config: stored,
|
|
source: 'env',
|
|
updatedAt: null,
|
|
updatedBy: null,
|
|
formula: '最终扣费 = 上游成本(USD) × 汇率 × 毛利倍数',
|
|
}),
|
|
updateAdminConfig: async (patch, context) => {
|
|
stored = { ...stored, ...(patch.config ?? patch) };
|
|
return {
|
|
config: stored,
|
|
source: 'admin-db',
|
|
updatedAt: Date.now(),
|
|
updatedBy: context?.updatedBy ?? null,
|
|
formula: '最终扣费 = 上游成本(USD) × 汇率 × 毛利倍数',
|
|
};
|
|
},
|
|
getRuntimeState: async () => ({
|
|
source: 'admin-db',
|
|
config: stored,
|
|
compute: stored,
|
|
}),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
async function startApp(options) {
|
|
const harness = createServices(options);
|
|
const server = createAdminApp(harness.services).listen(0, '127.0.0.1');
|
|
await once(server, 'listening');
|
|
const address = server.address();
|
|
assert.ok(address && typeof address === 'object');
|
|
return {
|
|
...harness,
|
|
request: (path, init = {}) => fetch(`http://127.0.0.1:${address.port}${path}`, {
|
|
...init,
|
|
headers: {
|
|
Cookie: 'test_session=token',
|
|
'Content-Type': 'application/json',
|
|
...init.headers,
|
|
},
|
|
}),
|
|
async close() {
|
|
server.close();
|
|
await once(server, 'close');
|
|
},
|
|
};
|
|
}
|
|
|
|
test('admin can read and update billing formula config', async (t) => {
|
|
const app = await startApp();
|
|
t.after(() => app.close());
|
|
|
|
const read = await app.request('/admin-api/billing/config');
|
|
assert.equal(read.status, 200);
|
|
const body = await read.json();
|
|
assert.equal(body.config.marginMultiplier, 1.2);
|
|
|
|
const update = await app.request('/admin-api/billing/config', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({
|
|
config: {
|
|
...body.config,
|
|
marginMultiplier: 1.5,
|
|
},
|
|
}),
|
|
});
|
|
assert.equal(update.status, 200);
|
|
const updated = await update.json();
|
|
assert.equal(updated.config.marginMultiplier, 1.5);
|
|
assert.equal(updated.source, 'admin-db');
|
|
});
|
|
|
|
test('ordinary users cannot access billing formula config', async (t) => {
|
|
const app = await startApp({ role: 'user' });
|
|
t.after(() => app.close());
|
|
|
|
const read = await app.request('/admin-api/billing/config');
|
|
assert.equal(read.status, 403);
|
|
});
|