新增财务申请时间类型筛选
This commit is contained in:
@@ -23,7 +23,9 @@ const FINANCE_EVENTS_CTE = `
|
||||
o.total_amount::bigint AS amount,
|
||||
'订单收款'::text AS label,
|
||||
o.platform_order_id::text AS reference_no,
|
||||
COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text AS channel
|
||||
COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text AS channel,
|
||||
o.created_at AS request_created_at,
|
||||
NULL::timestamptz AS request_reviewed_at
|
||||
FROM orders o
|
||||
WHERE o.pay_status IN ('paid', 'refunded')
|
||||
AND o.total_amount > 0
|
||||
@@ -37,7 +39,9 @@ const FINANCE_EVENTS_CTE = `
|
||||
o.total_amount::bigint,
|
||||
'订单退款'::text,
|
||||
o.platform_order_id::text,
|
||||
COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text
|
||||
COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text,
|
||||
o.created_at,
|
||||
NULL::timestamptz
|
||||
FROM orders o
|
||||
WHERE o.pay_status = 'refunded'
|
||||
AND o.total_amount > 0
|
||||
@@ -53,7 +57,9 @@ const FINANCE_EVENTS_CTE = `
|
||||
CASE WHEN wl.ledger_type IN ('reward_settlement', 'sharing_reward')
|
||||
THEN '打手报酬' ELSE '打手资金回收' END::text,
|
||||
COALESCE(wl.related_work_order_id::text, ''),
|
||||
'worker-platform'::text
|
||||
'worker-platform'::text,
|
||||
wl.created_at,
|
||||
NULL::timestamptz
|
||||
FROM worker_wallet_ledgers wl
|
||||
WHERE wl.ledger_type IN (
|
||||
'reward_settlement', 'sharing_reward', 'after_sales_deposit_deduction',
|
||||
@@ -70,7 +76,9 @@ const FINANCE_EVENTS_CTE = `
|
||||
wfr.amount::bigint,
|
||||
'打手提现'::text,
|
||||
wfr.account_channel::text,
|
||||
COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text
|
||||
COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text,
|
||||
wfr.created_at,
|
||||
wfr.reviewed_at
|
||||
FROM worker_finance_requests wfr
|
||||
WHERE wfr.request_type = 'withdraw'
|
||||
AND wfr.status = 'approved'
|
||||
@@ -86,7 +94,9 @@ const FINANCE_EVENTS_CTE = `
|
||||
wfr.amount::bigint,
|
||||
'打手充值'::text,
|
||||
wfr.account_channel::text,
|
||||
COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text
|
||||
COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text,
|
||||
wfr.created_at,
|
||||
wfr.reviewed_at
|
||||
FROM worker_finance_requests wfr
|
||||
WHERE wfr.request_type = 'recharge'
|
||||
AND wfr.status = 'approved'
|
||||
@@ -102,7 +112,9 @@ const FINANCE_EVENTS_CTE = `
|
||||
wasc.refunded_amount::bigint,
|
||||
'售后追缴退还'::text,
|
||||
wasc.case_no::text,
|
||||
'worker-platform'::text
|
||||
'worker-platform'::text,
|
||||
wasc.created_at,
|
||||
NULL::timestamptz
|
||||
FROM worker_after_sales_cases wasc
|
||||
WHERE wasc.refunded_at IS NOT NULL
|
||||
AND wasc.refunded_amount > 0
|
||||
@@ -111,6 +123,8 @@ const FINANCE_EVENTS_CTE = `
|
||||
|
||||
export async function getAdminFinanceSummary(payload: JsonObject = {}) {
|
||||
const range = resolveFinanceRange(payload, nowIso())
|
||||
const dateType = normalizeFinanceDateType(payload.dateType)
|
||||
const eventDateExpression = resolveFinanceEventDateExpression(dateType)
|
||||
const [dailyResult, snapshotResult] = await Promise.all([
|
||||
query<FinanceDailyRow>(
|
||||
`${FINANCE_EVENTS_CTE}
|
||||
@@ -126,10 +140,10 @@ export async function getAdminFinanceSummary(payload: JsonObject = {}) {
|
||||
COALESCE(SUM(amount) FILTER (WHERE category = 'worker_recovery'), 0)::bigint AS worker_recovery_amount
|
||||
FROM generate_series($3::timestamptz, $4::timestamptz - interval '1 day', interval '1 day') day
|
||||
LEFT JOIN finance_events event
|
||||
ON event.occurred_at >= $1::timestamptz
|
||||
AND event.occurred_at < $2::timestamptz
|
||||
AND event.occurred_at >= day
|
||||
AND event.occurred_at < day + interval '1 day'
|
||||
ON ${eventDateExpression} >= $1::timestamptz
|
||||
AND ${eventDateExpression} < $2::timestamptz
|
||||
AND ${eventDateExpression} >= day
|
||||
AND ${eventDateExpression} < day + interval '1 day'
|
||||
GROUP BY day
|
||||
ORDER BY day DESC`,
|
||||
[range.from, range.to, range.bucketFrom, range.bucketTo],
|
||||
@@ -151,14 +165,14 @@ export async function getAdminFinanceSummary(payload: JsonObject = {}) {
|
||||
const channelDailyResult = await query<FinanceChannelDailyRow>(
|
||||
`${FINANCE_EVENTS_CTE}
|
||||
SELECT
|
||||
to_char(event.occurred_at AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS day,
|
||||
to_char(${eventDateExpression} AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS day,
|
||||
event.channel,
|
||||
event.category,
|
||||
COUNT(*)::int AS total,
|
||||
COALESCE(SUM(event.amount), 0)::bigint AS amount
|
||||
FROM finance_events event
|
||||
WHERE event.occurred_at >= $1::timestamptz
|
||||
AND event.occurred_at < $2::timestamptz
|
||||
WHERE ${eventDateExpression} >= $1::timestamptz
|
||||
AND ${eventDateExpression} < $2::timestamptz
|
||||
GROUP BY 1, 2, 3
|
||||
ORDER BY day DESC, event.channel ASC, event.category ASC`,
|
||||
[range.from, range.to],
|
||||
@@ -203,6 +217,8 @@ export async function getAdminFinanceSummary(payload: JsonObject = {}) {
|
||||
|
||||
export async function listAdminFinanceTransactions(payload: JsonObject = {}) {
|
||||
const range = resolveFinanceRange(payload, nowIso())
|
||||
const dateType = normalizeFinanceDateType(payload.dateType)
|
||||
const eventDateExpression = resolveFinanceEventDateExpression(dateType)
|
||||
const page = normalizePositiveInt(payload.page, 1)
|
||||
const pageSize = Math.min(normalizePositiveInt(payload.pageSize, 20), 100)
|
||||
const category = String(payload.category || '').trim()
|
||||
@@ -226,8 +242,8 @@ export async function listAdminFinanceTransactions(payload: JsonObject = {}) {
|
||||
`${FINANCE_EVENTS_CTE}
|
||||
SELECT COUNT(*)::int AS total
|
||||
FROM finance_events event
|
||||
WHERE event.occurred_at >= $1
|
||||
AND event.occurred_at < $2${categoryClause}${channelClause}`,
|
||||
WHERE ${eventDateExpression} >= $1
|
||||
AND ${eventDateExpression} < $2${categoryClause}${channelClause}`,
|
||||
params,
|
||||
)
|
||||
const itemsParams = [...params, pageSize, offset]
|
||||
@@ -235,9 +251,9 @@ export async function listAdminFinanceTransactions(payload: JsonObject = {}) {
|
||||
`${FINANCE_EVENTS_CTE}
|
||||
SELECT category, source_id, occurred_at, amount, label, reference_no, channel
|
||||
FROM finance_events event
|
||||
WHERE event.occurred_at >= $1
|
||||
AND event.occurred_at < $2${categoryClause}${channelClause}
|
||||
ORDER BY event.occurred_at DESC, event.source_id DESC
|
||||
WHERE ${eventDateExpression} >= $1
|
||||
AND ${eventDateExpression} < $2${categoryClause}${channelClause}
|
||||
ORDER BY ${eventDateExpression} DESC, event.source_id DESC
|
||||
LIMIT $${itemsParams.length - 1} OFFSET $${itemsParams.length}`,
|
||||
itemsParams,
|
||||
)
|
||||
@@ -385,6 +401,18 @@ function normalizePositiveInt(value: unknown, fallback: number) {
|
||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
||||
}
|
||||
|
||||
function normalizeFinanceDateType(value: unknown): 'occurred' | 'created' | 'reviewed' {
|
||||
const normalized = String(value || '').trim()
|
||||
if (normalized === 'created' || normalized === 'reviewed') return normalized
|
||||
return 'occurred'
|
||||
}
|
||||
|
||||
function resolveFinanceEventDateExpression(dateType: 'occurred' | 'created' | 'reviewed') {
|
||||
if (dateType === 'created') return 'COALESCE(event.request_created_at, event.occurred_at)'
|
||||
if (dateType === 'reviewed') return 'event.request_reviewed_at'
|
||||
return 'event.occurred_at'
|
||||
}
|
||||
|
||||
function normalizeDateTimeDate(value: string) {
|
||||
const match = value.trim().match(/^(\d{4}-\d{2}-\d{2})/)
|
||||
if (!match || Number.isNaN(Date.parse(`${match[1]}T00:00:00Z`))) return ''
|
||||
|
||||
Reference in New Issue
Block a user