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