import { apiRequestData } from "./http"; export type RiskFlag = { id: string; entityType: string; entityId: string; riskCode: string; level: "low" | "medium" | "high"; title: string; detail: string | null; source: string; status: "open" | "resolved" | "dismissed"; payloadJson: Record | null; createdAt: string | null; createdBy: string | null; resolvedAt: string | null; resolvedBy: string | null; }; export type PrecheckDecision = "pass" | "warn" | "manual_review" | "block"; export type ExpenseStandardCheck = { itemId: string; expenseTypeId: string; expenseTypeName: string; amount: string; standardId: string; standardName: string; maxAmount: string; perUnit: "item" | "day" | "trip"; controlMode: "warn" | "block"; scopeType: "global" | "department"; scopeKey: string | null; exceeded: boolean; exceededAmount: string; }; export type PrecheckResponse = { entityType: "reimbursement" | "purchase_request" | "travel_request"; entityId: string; decision: PrecheckDecision; matchedBudgetControlRule: { id: string; name: string; controlMode: "warn" | "block" | "manual_review"; } | null; budgetHint: Record | null; standardChecks: ExpenseStandardCheck[]; evidenceSummary?: { invoiceCount: number; attachmentCount: number; items: Array<{ itemId: string; linkedInvoiceCount: number; invoiceState: "linked" | "unlinked"; }>; }; timelinessChecks?: Array<{ itemId: string; expenseDate: string; ageDays: number; maxAgeDays: 180 | 365; overdue: boolean; crossCalendarYear: boolean; }>; assetHint?: { required: boolean; itemCount: number }; warnings: Array<{ code: string; title: string; detail: string }>; blockingReasons: Array<{ code: string; title: string; detail: string }>; riskFlags: Array<{ code: string; level: "low" | "medium" | "high"; title: string; detail: string; willOpenOnSubmit: boolean }>; nextActions: string[]; }; export type RiskFlagListResponse = { items: RiskFlag[]; }; function buildRiskFlagsSearch(query: { entityType?: string; entityId?: string; status?: "open" | "resolved" | "dismissed"; source?: string; }) { const params = new URLSearchParams(); if (query.entityType) params.set("entityType", query.entityType); if (query.entityId) params.set("entityId", query.entityId); if (query.status) params.set("status", query.status); if (query.source) params.set("source", query.source); const search = params.toString(); return search ? `?${search}` : ""; } export async function precheckEntity(payload: { entityType: "reimbursement" | "purchase_request" | "travel_request"; entityId: string; }) { return apiRequestData("/api/fee-control/precheck", { method: "POST", body: JSON.stringify(payload), }); } export async function fetchRiskFlags(query: { entityType?: string; entityId?: string; status?: "open" | "resolved" | "dismissed"; source?: string; } = {}) { return apiRequestData(`/api/risk-flags${buildRiskFlagsSearch(query)}`); } export async function resolveRiskFlag(riskFlagId: string, payload: { note?: string | null } = {}) { return apiRequestData<{ item: RiskFlag }>(`/api/risk-flags/${riskFlagId}/resolve`, { method: "POST", body: JSON.stringify(payload), }); } export async function dismissRiskFlag(riskFlagId: string, payload: { note?: string | null } = {}) { return apiRequestData<{ item: RiskFlag }>(`/api/risk-flags/${riskFlagId}/dismiss`, { method: "POST", body: JSON.stringify(payload), }); }