修复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 assert from 'node:assert/strict'
import test from 'node:test' 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', () => { test('resolveOutstandingDepositAmount deducts released and deducted history', () => {
assert.equal( assert.equal(
@@ -25,3 +28,33 @@ test('resolveOutstandingDepositAmount never returns a negative deposit', () => {
) )
assert.equal(resolveOutstandingDepositAmount(null), 0) 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, workerId: number,
now: string, now: string,
): Promise<WorkerUserRow | null> { ): 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 }>( const acceptedResult = await client.query<{ total: number }>(
` `
SELECT SELECT
@@ -776,9 +797,14 @@ export async function maybeUpgradeWorkerLevelWithClient(
) )
const acceptedCount = Number(acceptedResult.rows[0]?.total || 0) 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 FROM worker_levels
WHERE status = 'active' WHERE status = 'active'
AND COALESCE((permission_json->>'upgradeThreshold')::int, 0) <= $1 AND COALESCE((permission_json->>'upgradeThreshold')::int, 0) <= $1
@@ -787,15 +813,19 @@ export async function maybeUpgradeWorkerLevelWithClient(
`, `,
[acceptedCount], [acceptedCount],
) )
const nextLevelId = Number(nextLevelResult.rows[0]?.id || 0) const nextLevel = nextLevelResult.rows[0]
const nextLevelId = Number(nextLevel?.id || 0)
if (!nextLevelId) return null if (!nextLevelId) return null
if (
const current = await client.query<{ id: number; level_id: number | null }>( !shouldApplyAutomaticWorkerLevel({
'SELECT id, level_id FROM worker_users WHERE id = $1 LIMIT 1', currentLevelId: currentRow.level_id,
[workerId], currentThreshold: Number(currentRow.upgrade_threshold || 0),
) candidateLevelId: nextLevelId,
const currentRow = current.rows[0] candidateThreshold: Number(nextLevel?.upgrade_threshold || 0),
if (!currentRow || Number(currentRow.level_id || 0) === nextLevelId) return null })
) {
return null
}
await client.query( await client.query(
'UPDATE worker_users SET level_id = $1, updated_at = $2 WHERE id = $3', '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) 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( async function getWorkerUserByIdWithClient(
client: PoolClient, client: PoolClient,
workerId: number | string, workerId: number | string,
@@ -147,6 +147,7 @@ export async function deleteAdminWorkCategory(categoryId: number | string) {
export async function saveAdminWorkerLevel(payload: JsonObject = {}) { export async function saveAdminWorkerLevel(payload: JsonObject = {}) {
const now = nowIso() const now = nowIso()
const levelKey = String(payload.levelKey || payload.level_key || '').trim() || DEFAULT_LEVEL_KEY 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 name = String(payload.name || '').trim() || DEFAULT_LEVEL_NAME
const permissions = { const permissions = {
depositFreeAmount: normalizeAmountFen( depositFreeAmount: normalizeAmountFen(
@@ -160,7 +161,7 @@ export async function saveAdminWorkerLevel(payload: JsonObject = {}) {
const level = await upsertWorkerLevel({ const level = await upsertWorkerLevel({
levelKey, levelKey,
name, name,
sortOrder: normalizeInteger(payload.sortOrder, 100), sortOrder: normalizeInteger(payload.sortOrder, Number(existingLevel?.sort_order || 100)),
status: String(payload.status || 'active').trim() === 'disabled' ? 'disabled' : 'active', status: String(payload.status || 'active').trim() === 'disabled' ? 'disabled' : 'active',
permissionJson: JSON.stringify(permissions), permissionJson: JSON.stringify(permissions),
now, now,