修复VIP自动成长降级

This commit is contained in:
yml2213
2026-08-16 14:54:43 +08:00
parent c4e7e67115
commit 75146e919d
3 changed files with 87 additions and 12 deletions
@@ -1,7 +1,10 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import { resolveOutstandingDepositAmount } from './worker-platform/index.js'
import {
resolveOutstandingDepositAmount,
shouldApplyAutomaticWorkerLevel,
} from './worker-platform/index.js'
test('resolveOutstandingDepositAmount deducts released and deducted history', () => {
assert.equal(
@@ -25,3 +28,33 @@ test('resolveOutstandingDepositAmount never returns a negative deposit', () => {
)
assert.equal(resolveOutstandingDepositAmount(null), 0)
})
test('automatic worker level changes only move to a higher threshold', () => {
assert.equal(
shouldApplyAutomaticWorkerLevel({
currentLevelId: 5,
currentThreshold: 100,
candidateLevelId: 1,
candidateThreshold: 0,
}),
false,
)
assert.equal(
shouldApplyAutomaticWorkerLevel({
currentLevelId: 1,
currentThreshold: 0,
candidateLevelId: 2,
candidateThreshold: 10,
}),
true,
)
assert.equal(
shouldApplyAutomaticWorkerLevel({
currentLevelId: 2,
currentThreshold: 10,
candidateLevelId: 3,
candidateThreshold: 10,
}),
false,
)
})
@@ -762,6 +762,27 @@ export async function maybeUpgradeWorkerLevelWithClient(
workerId: number,
now: string,
): Promise<WorkerUserRow | null> {
const current = await client.query<{
id: number
level_id: number | null
upgrade_threshold: number | null
}>(
`
SELECT
wu.id,
wu.level_id,
COALESCE((wl.permission_json->>'upgradeThreshold')::int, 0) AS upgrade_threshold
FROM worker_users wu
LEFT JOIN worker_levels wl ON wl.id = wu.level_id
WHERE wu.id = $1
LIMIT 1
FOR UPDATE OF wu
`,
[workerId],
)
const currentRow = current.rows[0]
if (!currentRow) return null
const acceptedResult = await client.query<{ total: number }>(
`
SELECT
@@ -776,9 +797,14 @@ export async function maybeUpgradeWorkerLevelWithClient(
)
const acceptedCount = Number(acceptedResult.rows[0]?.total || 0)
const nextLevelResult = await client.query<{ id: number }>(
const nextLevelResult = await client.query<{
id: number
upgrade_threshold: number
}>(
`
SELECT id
SELECT
id,
COALESCE((permission_json->>'upgradeThreshold')::int, 0) AS upgrade_threshold
FROM worker_levels
WHERE status = 'active'
AND COALESCE((permission_json->>'upgradeThreshold')::int, 0) <= $1
@@ -787,15 +813,19 @@ export async function maybeUpgradeWorkerLevelWithClient(
`,
[acceptedCount],
)
const nextLevelId = Number(nextLevelResult.rows[0]?.id || 0)
const nextLevel = nextLevelResult.rows[0]
const nextLevelId = Number(nextLevel?.id || 0)
if (!nextLevelId) return null
const current = await client.query<{ id: number; level_id: number | null }>(
'SELECT id, level_id FROM worker_users WHERE id = $1 LIMIT 1',
[workerId],
)
const currentRow = current.rows[0]
if (!currentRow || Number(currentRow.level_id || 0) === nextLevelId) return null
if (
!shouldApplyAutomaticWorkerLevel({
currentLevelId: currentRow.level_id,
currentThreshold: Number(currentRow.upgrade_threshold || 0),
candidateLevelId: nextLevelId,
candidateThreshold: Number(nextLevel?.upgrade_threshold || 0),
})
) {
return null
}
await client.query(
'UPDATE worker_users SET level_id = $1, updated_at = $2 WHERE id = $3',
@@ -818,6 +848,17 @@ export async function maybeUpgradeWorkerLevelWithClient(
return getWorkerUserByIdWithClient(client, workerId)
}
export function shouldApplyAutomaticWorkerLevel(input: {
currentLevelId: number | null
currentThreshold: number
candidateLevelId: number
candidateThreshold: number
}) {
if (!input.currentLevelId) return true
if (Number(input.currentLevelId) === Number(input.candidateLevelId)) return false
return Number(input.candidateThreshold) > Number(input.currentThreshold)
}
async function getWorkerUserByIdWithClient(
client: PoolClient,
workerId: number | string,
@@ -147,6 +147,7 @@ export async function deleteAdminWorkCategory(categoryId: number | string) {
export async function saveAdminWorkerLevel(payload: JsonObject = {}) {
const now = nowIso()
const levelKey = String(payload.levelKey || payload.level_key || '').trim() || DEFAULT_LEVEL_KEY
const existingLevel = await getWorkerLevelByKey(levelKey)
const name = String(payload.name || '').trim() || DEFAULT_LEVEL_NAME
const permissions = {
depositFreeAmount: normalizeAmountFen(
@@ -160,7 +161,7 @@ export async function saveAdminWorkerLevel(payload: JsonObject = {}) {
const level = await upsertWorkerLevel({
levelKey,
name,
sortOrder: normalizeInteger(payload.sortOrder, 100),
sortOrder: normalizeInteger(payload.sortOrder, Number(existingLevel?.sort_order || 100)),
status: String(payload.status || 'active').trim() === 'disabled' ? 'disabled' : 'active',
permissionJson: JSON.stringify(permissions),
now,