diff --git a/apps/backend/src/repositories/worker-platform/index.ts b/apps/backend/src/repositories/worker-platform/index.ts index 8d42af8b..fe86b937 100644 --- a/apps/backend/src/repositories/worker-platform/index.ts +++ b/apps/backend/src/repositories/worker-platform/index.ts @@ -3,6 +3,7 @@ export * from './shared.js' export * from './worker-repo.js' export * from './worker-session-repo.js' export * from './worker-level-repo.js' +export * from './worker-wallet-repo.js' export * from './work-order-repo.js' export * from './work-order-event-repo.js' export * from './work-order-share-repo.js' diff --git a/apps/backend/src/repositories/worker-platform/worker-repo.ts b/apps/backend/src/repositories/worker-platform/worker-repo.ts index e9a6a7d7..974d9b3d 100644 --- a/apps/backend/src/repositories/worker-platform/worker-repo.ts +++ b/apps/backend/src/repositories/worker-platform/worker-repo.ts @@ -4,12 +4,9 @@ import type { CreateWorkerInput, FinanceRequestListInput, ListInput, - WalletLedgerListInput, WorkerFinanceRequestRow, WorkerUserRow, WorkerWithdrawalAccountRow, - WorkerWalletLedgerRow, - WorkerWalletRow, } from './types.js' import type { PoolClient } from 'pg' @@ -289,102 +286,12 @@ export async function listWorkerUsers({ return { items: itemsResult.rows, total: Number(totalResult.rows[0]?.total || 0) } } -export async function ensureWorkerWallet( - workerId: number | string, - now: string, -): Promise { - return withTransaction(async (client) => { - await ensureWorkerWalletWithClient(client, Number(workerId), now) - return getWorkerWalletWithClient(client, Number(workerId)) - }) -} - -export async function getWorkerWallet(workerId: number | string): Promise { - const result = await query( - 'SELECT * FROM worker_wallets WHERE worker_id = $1 LIMIT 1', - [Number(workerId)], - ) - return result.rows[0] || null -} - -export async function listWorkerWalletLedgers({ - page = 1, - pageSize = 20, - workerId = 0, - ledgerType = '', -}: WalletLedgerListInput = {}): Promise<{ items: WorkerWalletLedgerRow[]; total: number }> { - const { whereClause, params } = buildWorkerWalletLedgerWhere({ - workerId, - ledgerType, - }) - const totalResult = await query<{ total: number }>( - `SELECT COUNT(*)::int AS total FROM worker_wallet_ledgers wwl ${whereClause}`, - params, - ) - const offset = (page - 1) * pageSize - params.push(pageSize, offset) - const itemsResult = await query( - ` - SELECT - wwl.*, - wo.platform_order_id AS related_platform_order_id - FROM worker_wallet_ledgers wwl - LEFT JOIN work_orders wo ON wo.id = wwl.related_work_order_id - ${whereClause} - ORDER BY wwl.created_at DESC, wwl.id DESC - LIMIT $${params.length - 1} OFFSET $${params.length} - `, - params, - ) - return { - items: itemsResult.rows, - total: Number(totalResult.rows[0]?.total || 0), - } -} - -export async function addWorkerWalletCredit(input: { - workerId: number - amount: number - note: string - payloadJson: string - now: string -}): Promise { - return withTransaction(async (client) => { - await ensureWorkerWalletWithClient(client, input.workerId, input.now) - const wallet = await getWorkerWalletWithClient(client, input.workerId) - const nextAvailable = Number(wallet?.available_amount || 0) + input.amount - const nextFrozen = Number(wallet?.frozen_deposit_amount || 0) - 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, input.amount, input.now, input.workerId], - ) - 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) - `, - [ - input.workerId, - input.amount, - nextAvailable, - nextFrozen, - input.note, - input.payloadJson, - input.now, - ], - ) - return getWorkerWalletWithClient(client, input.workerId) - }) -} +export { + addWorkerWalletCredit, + ensureWorkerWallet, + getWorkerWallet, + listWorkerWalletLedgers, +} from './worker-wallet-repo.js' export async function createWorkerFinanceRequest(input: { workerId: number @@ -1075,23 +982,6 @@ function buildWorkerUserWhere({ } } -function buildWorkerWalletLedgerWhere({ workerId = 0, ledgerType = '' }: WalletLedgerListInput) { - const filters: string[] = [] - const params: unknown[] = [] - if (workerId) { - params.push(workerId) - filters.push(`wwl.worker_id = $${params.length}`) - } - if (ledgerType) { - params.push(ledgerType) - filters.push(`wwl.ledger_type = $${params.length}`) - } - return { - whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '', - params, - } -} - function buildWorkerFinanceRequestWhere({ requestId = 0, workerId = 0, diff --git a/apps/backend/src/repositories/worker-platform/worker-wallet-repo.ts b/apps/backend/src/repositories/worker-platform/worker-wallet-repo.ts new file mode 100644 index 00000000..420ec853 --- /dev/null +++ b/apps/backend/src/repositories/worker-platform/worker-wallet-repo.ts @@ -0,0 +1,97 @@ +import { query, withTransaction } from '../../db/client.js' +import { ensureWorkerWalletWithClient, getWorkerWalletWithClient } from './shared.js' +import type { WalletLedgerListInput, WorkerWalletLedgerRow, WorkerWalletRow } from './types.js' + +export async function ensureWorkerWallet( + workerId: number | string, + now: string, +): Promise { + return withTransaction(async (client) => { + await ensureWorkerWalletWithClient(client, Number(workerId), now) + return getWorkerWalletWithClient(client, Number(workerId)) + }) +} + +export async function getWorkerWallet(workerId: number | string): Promise { + const result = await query( + 'SELECT * FROM worker_wallets WHERE worker_id = $1 LIMIT 1', + [Number(workerId)], + ) + return result.rows[0] || null +} + +export async function listWorkerWalletLedgers({ + page = 1, + pageSize = 20, + workerId = 0, + ledgerType = '', +}: WalletLedgerListInput = {}): Promise<{ items: WorkerWalletLedgerRow[]; total: number }> { + const { whereClause, params } = buildWorkerWalletLedgerWhere({ workerId, ledgerType }) + const totalResult = await query<{ total: number }>( + `SELECT COUNT(*)::int AS total FROM worker_wallet_ledgers wwl ${whereClause}`, + params, + ) + const offset = (page - 1) * pageSize + params.push(pageSize, offset) + const itemsResult = await query( + `SELECT wwl.*, wo.platform_order_id AS related_platform_order_id + FROM worker_wallet_ledgers wwl + LEFT JOIN work_orders wo ON wo.id = wwl.related_work_order_id + ${whereClause} + ORDER BY wwl.created_at DESC, wwl.id DESC + LIMIT $${params.length - 1} OFFSET $${params.length}`, + params, + ) + return { items: itemsResult.rows, total: Number(totalResult.rows[0]?.total || 0) } +} + +export async function addWorkerWalletCredit(input: { + workerId: number + amount: number + note: string + payloadJson: string + now: string +}): Promise { + return withTransaction(async (client) => { + await ensureWorkerWalletWithClient(client, input.workerId, input.now) + const wallet = await getWorkerWalletWithClient(client, input.workerId) + const nextAvailable = Number(wallet?.available_amount || 0) + input.amount + const nextFrozen = Number(wallet?.frozen_deposit_amount || 0) + 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, input.amount, input.now, input.workerId], + ) + 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)`, + [ + input.workerId, + input.amount, + nextAvailable, + nextFrozen, + input.note, + input.payloadJson, + input.now, + ], + ) + return getWorkerWalletWithClient(client, input.workerId) + }) +} + +function buildWorkerWalletLedgerWhere({ workerId = 0, ledgerType = '' }: WalletLedgerListInput) { + const filters: string[] = [] + const params: unknown[] = [] + if (workerId) { + params.push(workerId) + filters.push(`wwl.worker_id = $${params.length}`) + } + if (ledgerType) { + params.push(ledgerType) + filters.push(`wwl.ledger_type = $${params.length}`) + } + return { whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '', params } +}