feat(finance): 支持代录指定客服账户,并上线影子总账/对账/关账/快手平台退款
- 人工确认履约:管理员/财务/运营可传 fundAccountId / creditOwnerAdminUserId 指定客服备用金/积分账户;客服仍强制本人账户 - 新增迁移 112:finance_accounts / journal_entries / journal_lines / periods / reconciliations / reconciliation_items,种子 11 个科目 - 影子总账:销售事实按日生成收入/退款/成本凭证,支持手工凭证、试算平衡; 不接管钱包余额;总账同步接入定时任务与退款重算 - 期间关账/反关账:关账先补凭证并校验试算平衡,closed 期间禁止新增凭证 - 平台对账:JSON 账单导入,按 provider + platform_order_id 匹配订单/退款, 标记 matched/amount_mismatch/missing_order/missing_refund/duplicate - 平台退款:快手行业(91)同意退款 API 接入,成功后落 source=platform; 抖音/拼多多返回 501,保留手工退款 - 新增后台「财务 → 总账与对账」页面(总账/期间/对账三个 Tab) - 集成测试扩展到代录、总账平衡、关账阻断、手工凭证、对账匹配 验证:backend check 844(840 pass / 4 skip);frontend check 172 + build; 迁移 112 在 scratch 库全量执行并重跑幂等;本地生产副本已升级到 112, 销售事实同步 56 条凭证,借贷合计 1,885,351,864 = 1,885,351,864。
This commit is contained in:
@@ -458,6 +458,10 @@ export function confirmAdminManualFulfillment(payload: {
|
||||
costFen?: number
|
||||
payeeName?: string
|
||||
note?: string
|
||||
/** 管理员/财务代录:指定客服备用金账户 */
|
||||
fundAccountId?: number
|
||||
/** 管理员/财务代录:指定客服积分账户归属人 */
|
||||
creditOwnerAdminUserId?: number
|
||||
}) {
|
||||
return apiPost<ManualFulfillmentConfirmResult>(
|
||||
'/api/v1/admin/finance/manual-fulfillment/confirm',
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import { apiGet, apiPost } from '@/lib/http'
|
||||
import type {
|
||||
FinanceAccount,
|
||||
FinanceJournalEntry,
|
||||
FinancePeriod,
|
||||
FinanceReconciliation,
|
||||
FinanceReconciliationItem,
|
||||
FinanceTrialBalance,
|
||||
} from '@/types/admin/finance-ledger'
|
||||
|
||||
export function fetchFinanceAccounts() {
|
||||
return apiGet<{ items: FinanceAccount[] }>('/api/v1/admin/finance/ledger/accounts')
|
||||
}
|
||||
|
||||
export function fetchFinanceTrialBalance(params: { dateFrom: string; dateTo: string }) {
|
||||
return apiGet<FinanceTrialBalance>('/api/v1/admin/finance/ledger/trial-balance', params)
|
||||
}
|
||||
|
||||
export function fetchFinanceJournalEntries(params: {
|
||||
dateFrom?: string
|
||||
dateTo?: string
|
||||
page?: number
|
||||
pageSize?: number
|
||||
}) {
|
||||
return apiGet<{
|
||||
items: FinanceJournalEntry[]
|
||||
pagination: { page: number; pageSize: number; total: number }
|
||||
}>('/api/v1/admin/finance/ledger/entries', params)
|
||||
}
|
||||
|
||||
export function syncFinanceLedger(payload: { dateFrom?: string; dateTo?: string }) {
|
||||
return apiPost<{ created: number; skipped: number }>('/api/v1/admin/finance/ledger/sync', payload)
|
||||
}
|
||||
|
||||
export function createFinanceManualVoucher(payload: {
|
||||
occurredAt?: string
|
||||
memo?: string
|
||||
reference?: string
|
||||
lines: Array<{
|
||||
accountCode: string
|
||||
debitFen?: number
|
||||
creditFen?: number
|
||||
memo?: string
|
||||
}>
|
||||
}) {
|
||||
return apiPost<{ entryId: number; entryNo: string }>(
|
||||
'/api/v1/admin/finance/ledger/manual-voucher',
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
export function fetchFinancePeriods() {
|
||||
return apiGet<{ items: FinancePeriod[] }>('/api/v1/admin/finance/periods')
|
||||
}
|
||||
|
||||
export function closeFinancePeriod(periodKey: string) {
|
||||
return apiPost<{ periodKey: string }>(
|
||||
`/api/v1/admin/finance/periods/${encodeURIComponent(periodKey)}/close`,
|
||||
{},
|
||||
)
|
||||
}
|
||||
|
||||
export function reopenFinancePeriod(periodKey: string) {
|
||||
return apiPost<FinancePeriod>(
|
||||
`/api/v1/admin/finance/periods/${encodeURIComponent(periodKey)}/reopen`,
|
||||
{},
|
||||
)
|
||||
}
|
||||
|
||||
export function fetchFinanceReconciliations(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
provider?: string
|
||||
}) {
|
||||
return apiGet<{
|
||||
items: FinanceReconciliation[]
|
||||
pagination: { page: number; pageSize: number; total: number }
|
||||
}>('/api/v1/admin/finance/reconciliations', params)
|
||||
}
|
||||
|
||||
export function fetchFinanceReconciliation(id: number) {
|
||||
return apiGet<FinanceReconciliation & { items: FinanceReconciliationItem[] }>(
|
||||
`/api/v1/admin/finance/reconciliations/${id}`,
|
||||
)
|
||||
}
|
||||
|
||||
export function importFinanceReconciliation(payload: {
|
||||
provider: string
|
||||
periodFrom: string
|
||||
periodTo: string
|
||||
rows: Array<{
|
||||
platformOrderId: string
|
||||
entryType: 'sale' | 'refund'
|
||||
amountFen: number
|
||||
externalRef?: string
|
||||
occurredAt?: string
|
||||
}>
|
||||
}) {
|
||||
return apiPost<{
|
||||
reconciliationId: number
|
||||
status: string
|
||||
rows: number
|
||||
matched: number
|
||||
mismatched: number
|
||||
expectedFen: number
|
||||
actualFen: number
|
||||
diffFen: number
|
||||
}>('/api/v1/admin/finance/reconciliations/import', payload)
|
||||
}
|
||||
|
||||
export function resolveFinanceReconciliation(id: number, note: string) {
|
||||
return apiPost<FinanceReconciliation>(`/api/v1/admin/finance/reconciliations/${id}/resolve`, {
|
||||
note,
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './auth'
|
||||
export * from './dashboard'
|
||||
export * from './finance'
|
||||
export * from './finance-ledger'
|
||||
export * from './cost-center'
|
||||
export * from './fund'
|
||||
export * from './users'
|
||||
|
||||
Reference in New Issue
Block a user