修复VIP自动成长降级
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user