拆分打手资金仓储

This commit is contained in:
yml2213
2026-08-21 18:09:42 +08:00
parent 656bb5a2ce
commit ec29469fcb
3 changed files with 465 additions and 456 deletions
@@ -4,6 +4,7 @@ export * from './worker-repo.js'
export * from './worker-session-repo.js' export * from './worker-session-repo.js'
export * from './worker-level-repo.js' export * from './worker-level-repo.js'
export * from './worker-wallet-repo.js' export * from './worker-wallet-repo.js'
export * from './worker-finance-repo.js'
export * from './work-order-repo.js' export * from './work-order-repo.js'
export * from './work-order-event-repo.js' export * from './work-order-event-repo.js'
export * from './work-order-share-repo.js' export * from './work-order-share-repo.js'
@@ -0,0 +1,451 @@
import { query, withTransaction } from '../../db/client.js'
import { ensureWorkerWalletWithClient, getWorkerWalletWithClient } from './shared.js'
import type {
FinanceRequestListInput,
WorkerFinanceRequestRow,
WorkerWithdrawalAccountRow,
} from './types.js'
import type { PoolClient } from 'pg'
const WORKER_FINANCE_REQUEST_SELECT = `
SELECT
wfr.*,
wu.username AS worker_username,
wu.display_name AS worker_display_name,
wu.phone AS worker_phone,
wu.worker_type,
wl.level_key AS worker_level_key,
wl.name AS worker_level_name,
withdraw_stats.withdraw_request_count AS worker_withdraw_request_count,
withdraw_stats.total_withdraw_amount AS worker_total_withdraw_amount
FROM worker_finance_requests wfr
LEFT JOIN worker_users wu ON wu.id = wfr.worker_id
LEFT JOIN worker_levels wl ON wl.id = wu.level_id
LEFT JOIN LATERAL (
SELECT
COUNT(*)::int AS withdraw_request_count,
COALESCE(SUM(amount) FILTER (WHERE status = 'approved'), 0)::bigint AS total_withdraw_amount
FROM worker_finance_requests history_request
WHERE history_request.worker_id = wfr.worker_id
AND history_request.request_type = 'withdraw'
) withdraw_stats ON TRUE
`
export async function createWorkerFinanceRequest(input: {
workerId: number
requestType: string
amount: number
accountChannel: string
accountName: string
accountNo: string
note: string
payloadJson: string
now: string
}): Promise<WorkerFinanceRequestRow | null> {
const result = await query<WorkerFinanceRequestRow>(
`
INSERT INTO worker_finance_requests (
worker_id, request_type, status, amount,
account_channel, account_name, account_no,
note, reviewed_note, payload_json, created_at, updated_at
) VALUES ($1, $2, 'pending', $3, $4, $5, $6, $7, '', $8::jsonb, $9, $10)
RETURNING *
`,
[
input.workerId,
input.requestType,
input.amount,
input.accountChannel,
input.accountName,
input.accountNo,
input.note,
input.payloadJson,
input.now,
input.now,
],
)
return result.rows[0] || null
}
export async function getWorkerWithdrawalAccount(
workerId: number | string,
accountChannel: string,
): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
SELECT *
FROM worker_withdrawal_accounts
WHERE worker_id = $1 AND account_channel = $2
LIMIT 1
`,
[Number(workerId), accountChannel],
)
return result.rows[0] || null
}
export async function listWorkerWithdrawalAccounts(
workerId: number | string,
): Promise<WorkerWithdrawalAccountRow[]> {
const result = await query<WorkerWithdrawalAccountRow>(
`
SELECT *
FROM worker_withdrawal_accounts
WHERE worker_id = $1
ORDER BY account_channel ASC
`,
[Number(workerId)],
)
return result.rows
}
export async function createWorkerWithdrawalAccount(input: {
workerId: number
accountChannel: string
accountName: string
accountNo: string
alipayQrCodeJson: string
wechatQrCodeJson: string
now: string
}): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
INSERT INTO worker_withdrawal_accounts (
worker_id, account_channel, account_name, account_no,
alipay_qr_code_json, wechat_qr_code_json, created_at
) VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb, $7)
ON CONFLICT (worker_id, account_channel) DO NOTHING
RETURNING *
`,
[
input.workerId,
input.accountChannel,
input.accountName,
input.accountNo,
input.alipayQrCodeJson,
input.wechatQrCodeJson,
input.now,
],
)
return result.rows[0] || null
}
export async function upsertWorkerWithdrawalAccount(input: {
workerId: number
accountChannel: string
accountName: string
accountNo: string
alipayQrCodeJson: string
wechatQrCodeJson: string
now: string
}): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
INSERT INTO worker_withdrawal_accounts (
worker_id, account_channel, account_name, account_no,
alipay_qr_code_json, wechat_qr_code_json, created_at
) VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb, $7)
ON CONFLICT (worker_id, account_channel) DO UPDATE
SET
account_name = EXCLUDED.account_name,
account_no = EXCLUDED.account_no,
alipay_qr_code_json = EXCLUDED.alipay_qr_code_json,
wechat_qr_code_json = EXCLUDED.wechat_qr_code_json
RETURNING *
`,
[
input.workerId,
input.accountChannel,
input.accountName,
input.accountNo,
input.alipayQrCodeJson,
input.wechatQrCodeJson,
input.now,
],
)
return result.rows[0] || null
}
export async function getWorkerFinanceRequestById(
requestId: number | string,
): Promise<WorkerFinanceRequestRow | null> {
const result = await query<WorkerFinanceRequestRow>(
`${WORKER_FINANCE_REQUEST_SELECT} WHERE wfr.id = $1 LIMIT 1`,
[Number(requestId)],
)
return result.rows[0] || null
}
export async function countWorkerWithdrawRequestsOnDay(
workerId: number | string,
dayStartIso: string,
dayEndIso: string,
): Promise<number> {
const result = await query<{ total: number }>(
`
SELECT COUNT(*)::int AS total
FROM worker_finance_requests
WHERE worker_id = $1
AND request_type = 'withdraw'
AND status != 'cancelled'
AND created_at >= $2
AND created_at < $3
`,
[Number(workerId), dayStartIso, dayEndIso],
)
return Number(result.rows[0]?.total || 0)
}
export async function listWorkerFinanceRequests({
page = 1,
pageSize = 20,
requestId = 0,
workerId = 0,
status = '',
requestType = '',
keyword = '',
}: FinanceRequestListInput = {}): Promise<{ items: WorkerFinanceRequestRow[]; total: number }> {
const { whereClause, params } = buildWorkerFinanceRequestWhere({
requestId,
workerId,
status,
requestType,
keyword,
})
const totalResult = await query<{ total: number }>(
`SELECT COUNT(*)::int AS total FROM worker_finance_requests wfr
LEFT JOIN worker_users wu ON wu.id = wfr.worker_id
${whereClause}`,
params,
)
const offset = (page - 1) * pageSize
params.push(pageSize, offset)
const itemsResult = await query<WorkerFinanceRequestRow>(
`${WORKER_FINANCE_REQUEST_SELECT}
${whereClause}
ORDER BY wfr.created_at DESC, wfr.id DESC
LIMIT $${params.length - 1} OFFSET $${params.length}`,
params,
)
return {
items: itemsResult.rows,
total: Number(totalResult.rows[0]?.total || 0),
}
}
export async function reviewWorkerFinanceRequest(input: {
requestId: number
status: string
reviewedNote: string
now: string
}): Promise<{
request: WorkerFinanceRequestRow | null
failureReason: 'request_not_pending' | 'withdraw_insufficient' | null
}> {
return withTransaction(async (client) => {
const currentResult = await client.query<WorkerFinanceRequestRow>(
`
SELECT *
FROM worker_finance_requests
WHERE id = $1
LIMIT 1
FOR UPDATE
`,
[input.requestId],
)
const current = currentResult.rows[0] || null
if (!current) return { request: null, failureReason: null }
if (current.status !== 'pending') {
return {
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
failureReason: 'request_not_pending',
}
}
if (input.status === 'approved') {
await ensureWorkerWalletWithClient(client, Number(current.worker_id), input.now)
const wallet = await getWorkerWalletWithClient(client, Number(current.worker_id))
const availableAmount = Number(wallet?.available_amount || 0)
const frozenAmount = Number(wallet?.frozen_deposit_amount || 0)
const amount = Number(current.amount || 0)
const note =
input.reviewedNote ||
(current.request_type === 'withdraw' ? '提现申请审核通过' : '充值申请审核通过')
if (current.request_type === 'withdraw') {
if (availableAmount < amount) {
return {
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
failureReason: 'withdraw_insufficient',
}
}
const nextAvailable = availableAmount - amount
await client.query(
`
UPDATE worker_wallets
SET available_amount = $1, updated_at = $2
WHERE worker_id = $3
`,
[nextAvailable, input.now, Number(current.worker_id)],
)
await client.query(
`
INSERT INTO worker_wallet_ledgers (
worker_id, ledger_type, amount, balance_after, frozen_after,
audit_status, note, payload_json, created_at
) VALUES ($1, 'withdraw_paid', $2, $3, $4, 'approved', $5, $6::jsonb, $7)
`,
[
Number(current.worker_id),
-amount,
nextAvailable,
frozenAmount,
note,
JSON.stringify({
requestId: Number(current.id),
requestType: current.request_type,
source: 'admin_finance_review',
}),
input.now,
],
)
} else {
const nextAvailable = availableAmount + amount
await client.query(
`
UPDATE worker_wallets
SET
available_amount = $1,
total_credited_amount = total_credited_amount + $2,
updated_at = $3
WHERE worker_id = $4
`,
[nextAvailable, amount, input.now, Number(current.worker_id)],
)
await client.query(
`
INSERT INTO worker_wallet_ledgers (
worker_id, ledger_type, amount, balance_after, frozen_after,
audit_status, note, payload_json, created_at
) VALUES ($1, 'manual_credit', $2, $3, $4, 'approved', $5, $6::jsonb, $7)
`,
[
Number(current.worker_id),
amount,
nextAvailable,
frozenAmount,
note,
JSON.stringify({
requestId: Number(current.id),
requestType: current.request_type,
source: 'admin_finance_review',
}),
input.now,
],
)
}
}
await client.query(
`
UPDATE worker_finance_requests
SET
status = $1,
reviewed_note = $2,
reviewed_at = $3,
updated_at = $3
WHERE id = $4
`,
[input.status, input.reviewedNote, input.now, input.requestId],
)
return {
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
failureReason: null,
}
})
}
export async function getWorkerFinanceRequestSummary(workerId: number | string) {
const result = await query<{
pending_withdraw_amount: number
approved_withdraw_amount: number
pending_recharge_amount: number
}>(
`
SELECT
COALESCE(
SUM(CASE WHEN request_type = 'withdraw' AND status = 'pending' THEN amount ELSE 0 END),
0
)::int AS pending_withdraw_amount,
COALESCE(
SUM(CASE WHEN request_type = 'withdraw' AND status = 'approved' THEN amount ELSE 0 END),
0
)::int AS approved_withdraw_amount,
COALESCE(
SUM(CASE WHEN request_type = 'recharge' AND status = 'pending' THEN amount ELSE 0 END),
0
)::int AS pending_recharge_amount
FROM worker_finance_requests
WHERE worker_id = $1
`,
[Number(workerId)],
)
return {
pendingWithdrawAmount: Number(result.rows[0]?.pending_withdraw_amount || 0),
approvedWithdrawAmount: Number(result.rows[0]?.approved_withdraw_amount || 0),
pendingRechargeAmount: Number(result.rows[0]?.pending_recharge_amount || 0),
}
}
async function getWorkerFinanceRequestByIdWithClient(
client: PoolClient,
requestId: number | string,
): Promise<WorkerFinanceRequestRow | null> {
const result = await client.query<WorkerFinanceRequestRow>(
`${WORKER_FINANCE_REQUEST_SELECT} WHERE wfr.id = $1 LIMIT 1`,
[Number(requestId)],
)
return result.rows[0] || null
}
function buildWorkerFinanceRequestWhere({
requestId = 0,
workerId = 0,
status = '',
requestType = '',
keyword = '',
}: FinanceRequestListInput) {
const filters: string[] = []
const params: unknown[] = []
if (requestId) {
params.push(requestId)
filters.push(`wfr.id = $${params.length}`)
}
if (workerId) {
params.push(workerId)
filters.push(`wfr.worker_id = $${params.length}`)
}
if (status) {
params.push(status)
filters.push(`wfr.status = $${params.length}`)
}
if (requestType) {
params.push(requestType)
filters.push(`wfr.request_type = $${params.length}`)
}
if (keyword) {
params.push(`%${keyword}%`)
filters.push(
`(wu.username ILIKE $${params.length}
OR wu.display_name ILIKE $${params.length}
OR wu.phone ILIKE $${params.length}
OR wfr.account_name ILIKE $${params.length}
OR wfr.account_no ILIKE $${params.length})`,
)
}
return {
whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '',
params,
}
}
@@ -1,13 +1,6 @@
import { query, withTransaction } from '../../db/client.js' import { query, withTransaction } from '../../db/client.js'
import { ensureWorkerWalletWithClient, getWorkerWalletWithClient } from './shared.js' import { ensureWorkerWalletWithClient, getWorkerWalletWithClient } from './shared.js'
import type { import type { CreateWorkerInput, ListInput, WorkerUserRow } from './types.js'
CreateWorkerInput,
FinanceRequestListInput,
ListInput,
WorkerFinanceRequestRow,
WorkerUserRow,
WorkerWithdrawalAccountRow,
} from './types.js'
import type { PoolClient } from 'pg' import type { PoolClient } from 'pg'
const WORKER_USER_SELECT = ` const WORKER_USER_SELECT = `
@@ -29,30 +22,6 @@ const WORKER_USER_SELECT = `
LEFT JOIN worker_wallets ww ON ww.worker_id = wu.id LEFT JOIN worker_wallets ww ON ww.worker_id = wu.id
` `
const WORKER_FINANCE_REQUEST_SELECT = `
SELECT
wfr.*,
wu.username AS worker_username,
wu.display_name AS worker_display_name,
wu.phone AS worker_phone,
wu.worker_type,
wl.level_key AS worker_level_key,
wl.name AS worker_level_name,
withdraw_stats.withdraw_request_count AS worker_withdraw_request_count,
withdraw_stats.total_withdraw_amount AS worker_total_withdraw_amount
FROM worker_finance_requests wfr
LEFT JOIN worker_users wu ON wu.id = wfr.worker_id
LEFT JOIN worker_levels wl ON wl.id = wu.level_id
LEFT JOIN LATERAL (
SELECT
COUNT(*)::int AS withdraw_request_count,
COALESCE(SUM(amount) FILTER (WHERE status = 'approved'), 0)::bigint AS total_withdraw_amount
FROM worker_finance_requests history_request
WHERE history_request.worker_id = wfr.worker_id
AND history_request.request_type = 'withdraw'
) withdraw_stats ON TRUE
`
export { export {
createWorkerSessionRecord, createWorkerSessionRecord,
getWorkerSessionBySessionId, getWorkerSessionBySessionId,
@@ -293,378 +262,18 @@ export {
listWorkerWalletLedgers, listWorkerWalletLedgers,
} from './worker-wallet-repo.js' } from './worker-wallet-repo.js'
export async function createWorkerFinanceRequest(input: { export {
workerId: number countWorkerWithdrawRequestsOnDay,
requestType: string createWorkerFinanceRequest,
amount: number createWorkerWithdrawalAccount,
accountChannel: string getWorkerFinanceRequestById,
accountName: string getWorkerFinanceRequestSummary,
accountNo: string getWorkerWithdrawalAccount,
note: string listWorkerFinanceRequests,
payloadJson: string listWorkerWithdrawalAccounts,
now: string reviewWorkerFinanceRequest,
}): Promise<WorkerFinanceRequestRow | null> { upsertWorkerWithdrawalAccount,
const result = await query<WorkerFinanceRequestRow>( } from './worker-finance-repo.js'
`
INSERT INTO worker_finance_requests (
worker_id, request_type, status, amount,
account_channel, account_name, account_no,
note, reviewed_note, payload_json, created_at, updated_at
) VALUES ($1, $2, 'pending', $3, $4, $5, $6, $7, '', $8::jsonb, $9, $10)
RETURNING *
`,
[
input.workerId,
input.requestType,
input.amount,
input.accountChannel,
input.accountName,
input.accountNo,
input.note,
input.payloadJson,
input.now,
input.now,
],
)
return result.rows[0] || null
}
export async function getWorkerWithdrawalAccount(
workerId: number | string,
accountChannel: string,
): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
SELECT *
FROM worker_withdrawal_accounts
WHERE worker_id = $1 AND account_channel = $2
LIMIT 1
`,
[Number(workerId), accountChannel],
)
return result.rows[0] || null
}
export async function listWorkerWithdrawalAccounts(
workerId: number | string,
): Promise<WorkerWithdrawalAccountRow[]> {
const result = await query<WorkerWithdrawalAccountRow>(
`
SELECT *
FROM worker_withdrawal_accounts
WHERE worker_id = $1
ORDER BY account_channel ASC
`,
[Number(workerId)],
)
return result.rows
}
export async function createWorkerWithdrawalAccount(input: {
workerId: number
accountChannel: string
accountName: string
accountNo: string
alipayQrCodeJson: string
wechatQrCodeJson: string
now: string
}): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
INSERT INTO worker_withdrawal_accounts (
worker_id, account_channel, account_name, account_no,
alipay_qr_code_json, wechat_qr_code_json, created_at
) VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb, $7)
ON CONFLICT (worker_id, account_channel) DO NOTHING
RETURNING *
`,
[
input.workerId,
input.accountChannel,
input.accountName,
input.accountNo,
input.alipayQrCodeJson,
input.wechatQrCodeJson,
input.now,
],
)
return result.rows[0] || null
}
export async function upsertWorkerWithdrawalAccount(input: {
workerId: number
accountChannel: string
accountName: string
accountNo: string
alipayQrCodeJson: string
wechatQrCodeJson: string
now: string
}): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
INSERT INTO worker_withdrawal_accounts (
worker_id, account_channel, account_name, account_no,
alipay_qr_code_json, wechat_qr_code_json, created_at
) VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb, $7)
ON CONFLICT (worker_id, account_channel) DO UPDATE
SET
account_name = EXCLUDED.account_name,
account_no = EXCLUDED.account_no,
alipay_qr_code_json = EXCLUDED.alipay_qr_code_json,
wechat_qr_code_json = EXCLUDED.wechat_qr_code_json
RETURNING *
`,
[
input.workerId,
input.accountChannel,
input.accountName,
input.accountNo,
input.alipayQrCodeJson,
input.wechatQrCodeJson,
input.now,
],
)
return result.rows[0] || null
}
export async function getWorkerFinanceRequestById(
requestId: number | string,
): Promise<WorkerFinanceRequestRow | null> {
const result = await query<WorkerFinanceRequestRow>(
`${WORKER_FINANCE_REQUEST_SELECT} WHERE wfr.id = $1 LIMIT 1`,
[Number(requestId)],
)
return result.rows[0] || null
}
export async function countWorkerWithdrawRequestsOnDay(
workerId: number | string,
dayStartIso: string,
dayEndIso: string,
): Promise<number> {
const result = await query<{ total: number }>(
`
SELECT COUNT(*)::int AS total
FROM worker_finance_requests
WHERE worker_id = $1
AND request_type = 'withdraw'
AND status != 'cancelled'
AND created_at >= $2
AND created_at < $3
`,
[Number(workerId), dayStartIso, dayEndIso],
)
return Number(result.rows[0]?.total || 0)
}
export async function listWorkerFinanceRequests({
page = 1,
pageSize = 20,
requestId = 0,
workerId = 0,
status = '',
requestType = '',
keyword = '',
}: FinanceRequestListInput = {}): Promise<{ items: WorkerFinanceRequestRow[]; total: number }> {
const { whereClause, params } = buildWorkerFinanceRequestWhere({
requestId,
workerId,
status,
requestType,
keyword,
})
const totalResult = await query<{ total: number }>(
`SELECT COUNT(*)::int AS total FROM worker_finance_requests wfr
LEFT JOIN worker_users wu ON wu.id = wfr.worker_id
${whereClause}`,
params,
)
const offset = (page - 1) * pageSize
params.push(pageSize, offset)
const itemsResult = await query<WorkerFinanceRequestRow>(
`${WORKER_FINANCE_REQUEST_SELECT}
${whereClause}
ORDER BY wfr.created_at DESC, wfr.id DESC
LIMIT $${params.length - 1} OFFSET $${params.length}`,
params,
)
return {
items: itemsResult.rows,
total: Number(totalResult.rows[0]?.total || 0),
}
}
export async function reviewWorkerFinanceRequest(input: {
requestId: number
status: string
reviewedNote: string
now: string
}): Promise<{
request: WorkerFinanceRequestRow | null
failureReason: 'request_not_pending' | 'withdraw_insufficient' | null
}> {
return withTransaction(async (client) => {
const currentResult = await client.query<WorkerFinanceRequestRow>(
`
SELECT *
FROM worker_finance_requests
WHERE id = $1
LIMIT 1
FOR UPDATE
`,
[input.requestId],
)
const current = currentResult.rows[0] || null
if (!current) {
return {
request: null,
failureReason: null,
}
}
if (current.status !== 'pending') {
return {
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
failureReason: 'request_not_pending',
}
}
if (input.status === 'approved') {
await ensureWorkerWalletWithClient(client, Number(current.worker_id), input.now)
const wallet = await getWorkerWalletWithClient(client, Number(current.worker_id))
const availableAmount = Number(wallet?.available_amount || 0)
const frozenAmount = Number(wallet?.frozen_deposit_amount || 0)
const amount = Number(current.amount || 0)
const note =
input.reviewedNote ||
(current.request_type === 'withdraw' ? '提现申请审核通过' : '充值申请审核通过')
if (current.request_type === 'withdraw') {
if (availableAmount < amount) {
return {
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
failureReason: 'withdraw_insufficient',
}
}
const nextAvailable = availableAmount - amount
await client.query(
`
UPDATE worker_wallets
SET available_amount = $1, updated_at = $2
WHERE worker_id = $3
`,
[nextAvailable, input.now, Number(current.worker_id)],
)
await client.query(
`
INSERT INTO worker_wallet_ledgers (
worker_id, ledger_type, amount, balance_after, frozen_after,
audit_status, note, payload_json, created_at
) VALUES ($1, 'withdraw_paid', $2, $3, $4, 'approved', $5, $6::jsonb, $7)
`,
[
Number(current.worker_id),
-amount,
nextAvailable,
frozenAmount,
note,
JSON.stringify({
requestId: Number(current.id),
requestType: current.request_type,
source: 'admin_finance_review',
}),
input.now,
],
)
} else {
const nextAvailable = availableAmount + amount
await client.query(
`
UPDATE worker_wallets
SET
available_amount = $1,
total_credited_amount = total_credited_amount + $2,
updated_at = $3
WHERE worker_id = $4
`,
[nextAvailable, amount, input.now, Number(current.worker_id)],
)
await client.query(
`
INSERT INTO worker_wallet_ledgers (
worker_id, ledger_type, amount, balance_after, frozen_after,
audit_status, note, payload_json, created_at
) VALUES ($1, 'manual_credit', $2, $3, $4, 'approved', $5, $6::jsonb, $7)
`,
[
Number(current.worker_id),
amount,
nextAvailable,
frozenAmount,
note,
JSON.stringify({
requestId: Number(current.id),
requestType: current.request_type,
source: 'admin_finance_review',
}),
input.now,
],
)
}
}
await client.query(
`
UPDATE worker_finance_requests
SET
status = $1,
reviewed_note = $2,
reviewed_at = $3,
updated_at = $3
WHERE id = $4
`,
[input.status, input.reviewedNote, input.now, input.requestId],
)
return {
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
failureReason: null,
}
})
}
export async function getWorkerFinanceRequestSummary(workerId: number | string) {
const result = await query<{
pending_withdraw_amount: number
approved_withdraw_amount: number
pending_recharge_amount: number
}>(
`
SELECT
COALESCE(
SUM(CASE WHEN request_type = 'withdraw' AND status = 'pending' THEN amount ELSE 0 END),
0
)::int AS pending_withdraw_amount,
COALESCE(
SUM(CASE WHEN request_type = 'withdraw' AND status = 'approved' THEN amount ELSE 0 END),
0
)::int AS approved_withdraw_amount,
COALESCE(
SUM(CASE WHEN request_type = 'recharge' AND status = 'pending' THEN amount ELSE 0 END),
0
)::int AS pending_recharge_amount
FROM worker_finance_requests
WHERE worker_id = $1
`,
[Number(workerId)],
)
return {
pendingWithdrawAmount: Number(result.rows[0]?.pending_withdraw_amount || 0),
approvedWithdrawAmount: Number(result.rows[0]?.approved_withdraw_amount || 0),
pendingRechargeAmount: Number(result.rows[0]?.pending_recharge_amount || 0),
}
}
/** 完成单数按源订单去重,拼单份数只影响收益,不增加完成单数。 */ /** 完成单数按源订单去重,拼单份数只影响收益,不增加完成单数。 */
export async function countWorkerAcceptedOrders(workerId: number | string): Promise<number> { export async function countWorkerAcceptedOrders(workerId: number | string): Promise<number> {
@@ -939,17 +548,6 @@ async function getWorkerUserByIdWithClient(
return result.rows[0] || null return result.rows[0] || null
} }
async function getWorkerFinanceRequestByIdWithClient(
client: PoolClient,
requestId: number | string,
): Promise<WorkerFinanceRequestRow | null> {
const result = await client.query<WorkerFinanceRequestRow>(
`${WORKER_FINANCE_REQUEST_SELECT} WHERE wfr.id = $1 LIMIT 1`,
[Number(requestId)],
)
return result.rows[0] || null
}
function buildWorkerUserWhere({ function buildWorkerUserWhere({
status = '', status = '',
keyword = '', keyword = '',
@@ -981,44 +579,3 @@ function buildWorkerUserWhere({
params, params,
} }
} }
function buildWorkerFinanceRequestWhere({
requestId = 0,
workerId = 0,
status = '',
requestType = '',
keyword = '',
}: FinanceRequestListInput) {
const filters: string[] = []
const params: unknown[] = []
if (requestId) {
params.push(requestId)
filters.push(`wfr.id = $${params.length}`)
}
if (workerId) {
params.push(workerId)
filters.push(`wfr.worker_id = $${params.length}`)
}
if (status) {
params.push(status)
filters.push(`wfr.status = $${params.length}`)
}
if (requestType) {
params.push(requestType)
filters.push(`wfr.request_type = $${params.length}`)
}
if (keyword) {
params.push(`%${keyword}%`)
filters.push(
`(wu.username ILIKE $${params.length}
OR wu.display_name ILIKE $${params.length}
OR wu.phone ILIKE $${params.length}
OR wfr.account_name ILIKE $${params.length}
OR wfr.account_no ILIKE $${params.length})`,
)
}
return {
whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '',
params,
}
}