FL6 完善财务台账与导出审计
这个提交包含在:
@@ -4,6 +4,9 @@ import type { RiskFlag } from "./feeControl";
|
||||
export type ApOperationsExportFormat = "csv" | "xlsx";
|
||||
export type ApOperationsRiskBucket = "all" | "exception" | "budget_overspend";
|
||||
export type ApOperationsPendingEntityType = "reimbursement" | "travel_order";
|
||||
export type FinanceLedgerStatus = "draft" | "reviewing" | "approved" | "paid" | "rejected" | "cancelled";
|
||||
export type FinanceLedgerPaymentStatus = "unpaid" | "paid";
|
||||
export type FinanceLedgerInvoiceStatus = "none" | "pending_ocr" | "ocr_failed" | "available" | "bound" | "archived";
|
||||
|
||||
export type ApPendingPaymentBatchSummary = {
|
||||
id: string;
|
||||
@@ -61,12 +64,87 @@ export async function fetchApOperations() {
|
||||
return apiRequestData<ApOperationsSummary>("/api/ap-operations");
|
||||
}
|
||||
|
||||
export type FinanceLedgerItem = {
|
||||
id: string;
|
||||
formNumber: string | null;
|
||||
reimbursementDate: string | null;
|
||||
status: FinanceLedgerStatus;
|
||||
totalAmount: string;
|
||||
description: string | null;
|
||||
owner: { id: string; employeeNo: string; name: string } | null;
|
||||
submitter: { id: string; employeeNo: string; name: string } | null;
|
||||
department: { id: string; name: string } | null;
|
||||
payment: {
|
||||
status: FinanceLedgerPaymentStatus;
|
||||
paymentVoucherNo: string | null;
|
||||
paymentDate: string | null;
|
||||
paymentChannel: string | null;
|
||||
paidAt: string | null;
|
||||
paidBy: { id: string; employeeNo: string; name: string } | null;
|
||||
};
|
||||
invoice: {
|
||||
status: FinanceLedgerInvoiceStatus | "mixed";
|
||||
counts: {
|
||||
total: number;
|
||||
pendingOcr: number;
|
||||
ocrFailed: number;
|
||||
available: number;
|
||||
bound: number;
|
||||
archived: number;
|
||||
usedComplete: number;
|
||||
};
|
||||
};
|
||||
attachmentCount: number;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type FinanceLedgerQuery = {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
status?: FinanceLedgerStatus;
|
||||
paymentStatus?: FinanceLedgerPaymentStatus;
|
||||
invoiceStatus?: FinanceLedgerInvoiceStatus;
|
||||
dateFrom?: string;
|
||||
dateTo?: string;
|
||||
q?: string;
|
||||
};
|
||||
|
||||
export type FinanceLedgerResponse = {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
items: FinanceLedgerItem[];
|
||||
};
|
||||
|
||||
function toQueryString(query: Record<string, string | number | undefined>) {
|
||||
const params = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value == null || value === "") continue;
|
||||
params.set(key, String(value));
|
||||
}
|
||||
const suffix = params.toString();
|
||||
return suffix ? `?${suffix}` : "";
|
||||
}
|
||||
|
||||
export async function fetchFinanceLedger(query: FinanceLedgerQuery = {}) {
|
||||
return apiRequestData<FinanceLedgerResponse>(
|
||||
`/api/ap-operations/reimbursement-ledger${toQueryString(query as Record<string, string | number | undefined>)}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function exportApOperations(params: {
|
||||
format: ApOperationsExportFormat;
|
||||
pendingEntityType?: ApOperationsPendingEntityType;
|
||||
pendingCreatedAtFrom?: string;
|
||||
pendingCreatedAtTo?: string;
|
||||
riskBucket?: ApOperationsRiskBucket;
|
||||
ledgerStatus?: FinanceLedgerStatus;
|
||||
ledgerPaymentStatus?: FinanceLedgerPaymentStatus;
|
||||
ledgerInvoiceStatus?: FinanceLedgerInvoiceStatus;
|
||||
ledgerDateFrom?: string;
|
||||
ledgerDateTo?: string;
|
||||
ledgerSearch?: string;
|
||||
}) {
|
||||
return apiRequestBlob("/api/exports/ap-operations", {
|
||||
method: "POST",
|
||||
|
||||
在新工单中引用
屏蔽一个用户