支持后台修改打手提现信息
This commit is contained in:
@@ -497,6 +497,38 @@ export async function createWorkerWithdrawalAccount(input: {
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function upsertWorkerWithdrawalAccount(input: {
|
||||
workerId: number
|
||||
accountChannel: string
|
||||
accountName: string
|
||||
accountNo: 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, wechat_qr_code_json, created_at
|
||||
) VALUES ($1, $2, $3, $4, $5::jsonb, $6)
|
||||
ON CONFLICT (worker_id, account_channel) DO UPDATE
|
||||
SET
|
||||
account_name = EXCLUDED.account_name,
|
||||
account_no = EXCLUDED.account_no,
|
||||
wechat_qr_code_json = EXCLUDED.wechat_qr_code_json
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
input.workerId,
|
||||
input.accountChannel,
|
||||
input.accountName,
|
||||
input.accountNo,
|
||||
input.wechatQrCodeJson,
|
||||
input.now,
|
||||
],
|
||||
)
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function getWorkerFinanceRequestById(
|
||||
requestId: number | string,
|
||||
): Promise<WorkerFinanceRequestRow | null> {
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
getAdminWorkOrderEvents,
|
||||
getAdminWorkOrderSharing,
|
||||
listAdminWorkerFinanceRequests,
|
||||
listAdminWorkerWithdrawalAccounts,
|
||||
listAdminWorkCategories,
|
||||
listAdminWorkProductRules,
|
||||
listAdminWorkerLevels,
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
resolveAdminProblemWorkOrder,
|
||||
reviewAdminWorkerUser,
|
||||
saveAdminWorkerFinanceConfig,
|
||||
saveAdminWorkerWithdrawalAccount,
|
||||
saveAdminWorkCategory,
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
@@ -227,6 +229,40 @@ router.post(
|
||||
),
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/worker-platform/workers/:workerId/withdrawal-accounts',
|
||||
requireAdminRoles(['admin', 'operator']),
|
||||
createJsonHandler((req) => listAdminWorkerWithdrawalAccounts(String(req.params.workerId || '')), {
|
||||
successMessage: 'ok',
|
||||
errorMessage: '读取打手提现信息失败',
|
||||
scope: '[admin/worker-platform/workers/:workerId/withdrawal-accounts]',
|
||||
}),
|
||||
)
|
||||
|
||||
router.post(
|
||||
'/worker-platform/workers/:workerId/withdrawal-accounts/:accountChannel',
|
||||
requireAdminRoles(['admin', 'operator']),
|
||||
createJsonHandler(
|
||||
(req) =>
|
||||
saveAdminWorkerWithdrawalAccount(
|
||||
String(req.params.workerId || ''),
|
||||
String(req.params.accountChannel || ''),
|
||||
req.body || {},
|
||||
),
|
||||
{
|
||||
successMessage: '打手提现信息已保存',
|
||||
errorMessage: '保存打手提现信息失败',
|
||||
scope: '[admin/worker-platform/workers/:workerId/withdrawal-accounts/:accountChannel]',
|
||||
audit: (req) => ({
|
||||
action: 'worker_withdrawal_account_saved',
|
||||
targetType: 'worker',
|
||||
targetId: String(req.params.workerId || ''),
|
||||
data: { accountChannel: String(req.params.accountChannel || '') },
|
||||
}),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/worker-platform/finance-config',
|
||||
requireAdminRoles(['admin', 'operator', 'support']),
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
listWorkProductRules,
|
||||
listWorkerLevels,
|
||||
listWorkerUsers,
|
||||
listWorkerWithdrawalAccounts,
|
||||
listWorkOrderShares,
|
||||
listWorkOrderSharesByOrderIds,
|
||||
sumPendingUnfreezeByOrderIds,
|
||||
@@ -40,11 +41,13 @@ import {
|
||||
updateWorkOrder,
|
||||
updateWorkOrderBasic,
|
||||
updateWorkerUser,
|
||||
upsertWorkerWithdrawalAccount,
|
||||
upsertWorkCategory,
|
||||
upsertWorkProductRule,
|
||||
upsertWorkerLevel,
|
||||
type WorkOrderRow,
|
||||
type WorkOrderShareRow,
|
||||
type WorkerWithdrawalAccountRow,
|
||||
} from '../../repositories/worker-platform/index.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||
@@ -53,6 +56,7 @@ import { randomId } from '../../utils/random.js'
|
||||
import { nowIso } from '../../utils/time.js'
|
||||
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
|
||||
import { getWorkerFinanceConfig, saveWorkerFinanceConfig } from './worker-finance-config-service.js'
|
||||
import { refreshUploadedFileUrls } from '../file-storage/file-storage-service.js'
|
||||
import {
|
||||
consumeIndustryVouchersBeforeWorkOrderAssign,
|
||||
consumeIndustryVouchersBeforeWorkOrderPublish,
|
||||
@@ -81,6 +85,7 @@ import {
|
||||
normalizeMatchType,
|
||||
normalizeOptionalId,
|
||||
normalizePositiveInteger,
|
||||
normalizeProofFiles,
|
||||
normalizeProblemResolutionAction,
|
||||
normalizeRequirementFields,
|
||||
normalizeRequirementFieldsFromPayload,
|
||||
@@ -91,6 +96,7 @@ import {
|
||||
normalizeSubmittedFields,
|
||||
normalizeUploadedFiles,
|
||||
normalizeWorkerType,
|
||||
normalizeWithdrawChannel,
|
||||
resolveFreezeDepositAmount,
|
||||
mapWorkOrderEvents,
|
||||
resolveMatchingProductRule,
|
||||
@@ -524,6 +530,71 @@ export async function creditAdminWorkerWallet(workerId: number | string, payload
|
||||
return { wallet: mapWallet(wallet) }
|
||||
}
|
||||
|
||||
export async function listAdminWorkerWithdrawalAccounts(workerId: number | string) {
|
||||
const worker = await getRequiredWorker(workerId)
|
||||
const items = await listWorkerWithdrawalAccounts(worker.id)
|
||||
return {
|
||||
worker: mapWorkerUser(worker),
|
||||
items: items.map(mapAdminWorkerWithdrawalAccount),
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveAdminWorkerWithdrawalAccount(
|
||||
workerId: number | string,
|
||||
accountChannelValue: unknown,
|
||||
payload: JsonObject = {},
|
||||
) {
|
||||
const worker = await getRequiredWorker(workerId)
|
||||
const accountChannel = normalizeWithdrawChannel(accountChannelValue)
|
||||
const currentAccounts = await listWorkerWithdrawalAccounts(worker.id)
|
||||
const current = currentAccounts.find((item) => item.account_channel === accountChannel)
|
||||
const accountName = String(payload.accountName || payload.realName || '').trim()
|
||||
const accountNo =
|
||||
accountChannel === 'alipay' ? String(payload.accountNo || payload.account || '').trim() : ''
|
||||
const uploadedWechatQrCode = normalizeProofFiles(
|
||||
payload.wechatQrCodeImages || payload.wechatQrCodes,
|
||||
)[0]
|
||||
const wechatQrCodeImage =
|
||||
accountChannel === 'wechat'
|
||||
? uploadedWechatQrCode || safeParseJson(current?.wechat_qr_code_json)
|
||||
: {}
|
||||
|
||||
if (!accountName) {
|
||||
throw createHttpError('请填写收款人姓名', {
|
||||
statusCode: 400,
|
||||
errorCode: 'admin_worker_withdraw_account_name_required',
|
||||
})
|
||||
}
|
||||
if (accountChannel === 'alipay' && !accountNo) {
|
||||
throw createHttpError('请填写支付宝账号', {
|
||||
statusCode: 400,
|
||||
errorCode: 'admin_worker_withdraw_alipay_account_required',
|
||||
})
|
||||
}
|
||||
if (accountChannel === 'wechat' && !String(wechatQrCodeImage.url || '').trim()) {
|
||||
throw createHttpError('请上传微信收款二维码', {
|
||||
statusCode: 400,
|
||||
errorCode: 'admin_worker_withdraw_wechat_qr_required',
|
||||
})
|
||||
}
|
||||
|
||||
const saved = await upsertWorkerWithdrawalAccount({
|
||||
workerId: worker.id,
|
||||
accountChannel,
|
||||
accountName,
|
||||
accountNo,
|
||||
wechatQrCodeJson: JSON.stringify(wechatQrCodeImage),
|
||||
now: nowIso(),
|
||||
})
|
||||
if (!saved) {
|
||||
throw createHttpError('保存打手提现信息失败', {
|
||||
statusCode: 500,
|
||||
errorCode: 'admin_worker_withdraw_account_save_failed',
|
||||
})
|
||||
}
|
||||
return { account: mapAdminWorkerWithdrawalAccount(saved) }
|
||||
}
|
||||
|
||||
export async function getAdminWorkerFinanceConfig() {
|
||||
return getWorkerFinanceConfig()
|
||||
}
|
||||
@@ -599,6 +670,17 @@ export async function reviewAdminWorkerFinanceRequest(
|
||||
}
|
||||
}
|
||||
|
||||
function mapAdminWorkerWithdrawalAccount(account: WorkerWithdrawalAccountRow) {
|
||||
const wechatQrCodeImage = refreshUploadedFileUrls(safeParseJson(account.wechat_qr_code_json))
|
||||
return {
|
||||
accountChannel: account.account_channel,
|
||||
accountName: account.account_name,
|
||||
accountNo: account.account_channel === 'alipay' ? account.account_no : '',
|
||||
wechatQrCodeImage: String(wechatQrCodeImage.url || '').trim() ? wechatQrCodeImage : null,
|
||||
createdAt: account.created_at,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAdminWorkOrderEvents(workOrderId: number | string) {
|
||||
await getRequiredWorkOrder(workOrderId)
|
||||
const events = await listWorkOrderEventsByOrderId(workOrderId)
|
||||
|
||||
Reference in New Issue
Block a user