This commit is contained in:
2026-08-11 18:17:05 +08:00
parent 61d9673f15
commit 6456278ec8
2 changed files with 139 additions and 1 deletions
+48 -1
View File
@@ -1,9 +1,26 @@
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
import type { FinanceAccountEntry, FinanceBillDetail, FinanceBillLine, FinanceBillResource, FinanceBillRevision, FinanceCostResource, FinanceCustomerAccountReadModel, FinanceCustomerTerms, FinanceFeePoolItem, FinancePayableSettlement, FinanceReceivableSettlement, FinanceReceiptResource, FinanceStatementReadModel, FinanceVoucherResource } from '../types'
import type { FinanceAccountEntry, FinanceAccountSummary, FinanceBillDetail, FinanceBillLine, FinanceBillResource, FinanceBillRevision, FinanceCostResource, FinanceCustomerAccountReadModel, FinanceCustomerTerms, FinanceFeePoolItem, FinanceFeeSourceDetail, FinanceLedgerEntry, FinancePayableSettlement, FinanceReceivableSettlement, FinanceReceiptResource, FinanceSettlementDetail, FinanceStatementReadModel, FinanceVoucherResource } from '../types'
const basePath = '/platform/finance/v1'
export const financePhase1Capabilities = {
accountList: false,
accountLedger: false,
feeSourceDetail: false,
feeSourceReview: false,
feeSourceSettlementInclusion: false,
reconciliationCreate: false,
reconciliationActions: false,
receivableSettlementCreate: false,
payableSettlementCreate: false,
settlementDetail: false,
settlementPayment: false,
} as const
function idempotencyKey(operation: string) { return `finance-${operation}-${Date.now()}-${Math.random().toString(36).slice(2)}` }
type RawResource = Record<string, unknown>
export class FinanceCapabilityBlockedError extends Error {
readonly code = 'FINANCE_NOT_IMPLEMENTED'
constructor(operation: string) { super(`接口尚未提供,暂不可操作:${operation}`); this.name = 'FinanceCapabilityBlockedError' }
}
function stringValue(value: unknown) { return value == null ? '' : String(value) }
function numberValue(value: unknown) { return Number(value ?? 0) }
@@ -56,6 +73,36 @@ export async function listFinanceFeePool(customerId: string, direction?: 'RECEIV
return unwrapApiResponse(response).map((item) => ({ poolItemId: stringValue(item.poolItemId), direction: stringValue(item.direction) as FinanceFeePoolItem['direction'], sourceType: stringValue(item.sourceType), sourceId: stringValue(item.sourceId), sourceVersion: numberValue(item.sourceVersion), orderId: item.orderId == null ? null : stringValue(item.orderId), inboundId: item.inboundId == null ? null : stringValue(item.inboundId), containerId: item.containerId == null ? null : stringValue(item.containerId), feeItemName: stringValue(item.feeItemName), amount: numberValue(item.amount), currency: 'CNY', status: stringValue(item.status), createdAt: stringValue(item.createdAt) }))
}
export async function listFinanceAccounts(params: { page?: number; size?: number; keyword?: string; status?: string } = {}): Promise<{ records: FinanceAccountSummary[]; total: number; pages: number }> {
const response = await http.get<ApiEnvelope<RawResource>, ApiEnvelope<RawResource>>(`${basePath}/accounts`, { params })
const data = unwrapApiResponse(response) as RawResource
const records = (Array.isArray(data.records) ? data.records : Array.isArray(data.items) ? data.items : []).map((item) => ({ customerId: stringValue(item.customerId ?? item.customer_id), customerName: stringValue(item.customerName ?? item.customer_name), customerStatus: stringValue(item.customerStatus ?? item.status), currency: 'CNY' as const, totalReceivable: numberValue(item.totalReceivable ?? item.total_receivable), receivedAmount: numberValue(item.receivedAmount ?? item.totalReceived ?? item.received_amount), outstandingAmount: numberValue(item.outstandingAmount ?? item.outstanding_amount), creditDays: numberValue(item.creditDays ?? item.credit_days ?? 30) }))
return { records, total: numberValue(data.total ?? records.length), pages: numberValue(data.pages ?? 1) || 1 }
}
export async function listFinanceAccountLedger(customerId: string, params: { page?: number; size?: number; businessType?: string; startDate?: string; endDate?: string } = {}): Promise<{ records: FinanceLedgerEntry[]; total: number; pages: number }> {
const response = await http.get<ApiEnvelope<RawResource>, ApiEnvelope<RawResource>>(`${basePath}/accounts/${customerId}/ledger`, { params })
const data = unwrapApiResponse(response) as RawResource
const records = (Array.isArray(data.records) ? data.records : Array.isArray(data.items) ? data.items : []).map((item) => ({ entryId: stringValue(item.entryId ?? item.id), businessType: stringValue(item.businessType), resourceId: stringValue(item.resourceId), resourceNo: stringValue(item.resourceNo), occurredAt: stringValue(item.occurredAt), debitAmount: numberValue(item.debitAmount), creditAmount: numberValue(item.creditAmount), balance: numberValue(item.balance), currency: 'CNY' as const, status: stringValue(item.status) }))
return { records, total: numberValue(data.total ?? records.length), pages: numberValue(data.pages ?? 1) || 1 }
}
export async function getFinanceFeeSource(feeSourceId: string): Promise<FinanceFeeSourceDetail> {
const response = await http.get<ApiEnvelope<RawResource>, ApiEnvelope<RawResource>>(`${basePath}/fee-sources/${feeSourceId}`)
const item = unwrapApiResponse(response)
const pool = (await Promise.resolve([item])).map((raw) => ({ poolItemId: stringValue(raw.poolItemId ?? raw.id), direction: stringValue(raw.direction) as FinanceFeePoolItem['direction'], sourceType: stringValue(raw.sourceType), sourceId: stringValue(raw.sourceId), sourceVersion: numberValue(raw.sourceVersion) || 1, orderId: raw.orderId == null ? null : stringValue(raw.orderId), inboundId: raw.inboundId == null ? null : stringValue(raw.inboundId), containerId: raw.containerId == null ? null : stringValue(raw.containerId), feeItemName: stringValue(raw.feeItemName), amount: numberValue(raw.amount), currency: 'CNY' as const, status: stringValue(raw.status), createdAt: stringValue(raw.createdAt) }))[0]
return { ...pool, reviewStatus: stringValue(item.reviewStatus), settlementIncluded: Boolean(item.settlementIncluded), sourceStatus: stringValue(item.sourceStatus), reviewReason: stringValue(item.reviewReason), settlementReason: stringValue(item.settlementReason), sourceHash: stringValue(item.sourceHash), operationLogs: Array.isArray(item.operationLogs) ? item.operationLogs as FinanceFeeSourceDetail['operationLogs'] : [], version: numberValue(item.version) }
}
export async function reviewFinanceFeeSource(feeSourceId: string, payload: { action: 'APPROVE' | 'REJECT'; reason?: string; expectedVersion: number }) { throw new FinanceCapabilityBlockedError('reviewFinanceFeeSource') }
export async function updateFinanceFeeSourceSettlementInclusion(feeSourceId: string, payload: { included: boolean; reason: string; expectedVersion: number }) { throw new FinanceCapabilityBlockedError('updateFeeSourceSettlementInclusion') }
export async function createReconciliationStatement(payload: Record<string, unknown>) { throw new FinanceCapabilityBlockedError('createReconciliationStatement') }
export async function actionReconciliationStatement(statementId: string, payload: Record<string, unknown>) { throw new FinanceCapabilityBlockedError('actionReconciliationStatement') }
export async function createReceivableSettlement(payload: Record<string, unknown>) { throw new FinanceCapabilityBlockedError('createReceivableSettlement') }
export async function createPayableSettlement(payload: Record<string, unknown>) { throw new FinanceCapabilityBlockedError('createPayableSettlement') }
export async function getFinanceSettlement(settlementId: string): Promise<FinanceSettlementDetail> { throw new FinanceCapabilityBlockedError('getSettlement') }
export async function createFinanceSettlementPayment(settlementId: string, payload: Record<string, unknown>) { throw new FinanceCapabilityBlockedError('createSettlementPayment') }
export async function listFinanceStatements(customerId: string): Promise<FinanceStatementReadModel[]> {
const response = await http.get<ApiEnvelope<RawResource[]>, ApiEnvelope<RawResource[]>>(`${basePath}/statements`, { params: { customerId } })
return unwrapApiResponse(response).map((item) => ({ id: stringValue(item.id), customerId: stringValue(item.customerId), billNo: stringValue(item.billNo), customerName: stringValue(item.customerName), billDate: stringValue(item.billDate), dueDate: stringValue(item.dueDate), totalAmount: numberValue(item.totalAmount), receivedAmount: numberValue(item.receivedAmount), outstandingAmount: numberValue(item.outstandingAmount), currency: 'CNY', status: stringValue(item.status) as FinanceStatementReadModel['status'], version: numberValue(item.version) }))