import { apiRequestData } from "./http"; export type InvoicePoolStatus = "pending_ocr" | "ocr_failed" | "available" | "bound" | "archived"; export type InvoiceVerificationRecord = { id: string; provider: string; status: string; resultCode: string | null; resultMessage: string | null; errorCode: string | null; errorMessage: string | null; durationMs: number | null; requestedBy: string | null; requestedAt: string | null; completedAt: string | null; retryOfId: string | null; attempts: number; }; export type InvoicePoolListItem = { id: string; status: InvoicePoolStatus; ocrType: string; ocrProvider: string; ocrAttempts: number; ocrLastError: string | null; ocrCompletedAt: string | null; invoiceCode: string | null; invoiceNumber: string | null; invoiceDate: string | null; amount: string | null; taxAmount: string | null; totalAmount: string | null; linkedReimbursementId: string | null; linkedItemId: string | null; linkedTravelOrderId: string | null; originalName: string; mimeType: string; fileSize: number; verification: InvoiceVerificationRecord | null; owner: { id: string; employeeNo: string; name: string; } | null; uploadedBy: { id: string; employeeNo: string; name: string; } | null; createdAt: string | null; updatedAt: string | null; }; export type InvoicePoolListResponse = { page: number; pageSize: number; total: number; ownerScope: "own" | "all"; items: InvoicePoolListItem[]; }; export type InvoicePoolDetail = { id: string; status: InvoicePoolStatus; archivedReason: string | null; archivedAt: string | null; ownerEmployeeId: string; uploadedByEmployeeId: string; originalName: string | null; mimeType: string | null; fileSize: number | null; fileSha256: string | null; remarks: string | null; ocrType: string; ocrProvider: string; ocrAttempts: number; ocrLastRequestedAt: string | null; ocrLastError: string | null; ocrCompletedAt: string | null; invoiceCode: string | null; invoiceNumber: string | null; invoiceDate: string | null; sellerName: string | null; buyerName: string | null; amount: string | null; taxAmount: string | null; totalAmount: string | null; linkedReimbursementId: string | null; linkedItemId: string | null; linkedTravelOrderId: string | null; isDuplicateOverride: boolean; overrideRefFormNumber: string | null; overrideReason: string | null; overriddenBy: string | null; verification: InvoiceVerificationRecord | null; createdAt: string | null; updatedAt: string | null; }; export type InvoicePoolListQuery = { page?: number; pageSize?: number; status?: InvoicePoolStatus; ownerScope?: "own" | "all"; }; export type InvoiceBindPayload = | { reimbursementId: string; linkedItemId?: string; } | { travelOrderId: string; }; function toQueryString(query: Record) { const params = new URLSearchParams(); for (const [key, value] of Object.entries(query)) { if (value == null || value === "") { continue; } params.set(key, String(value)); } const encoded = params.toString(); return encoded ? `?${encoded}` : ""; } export async function fetchInvoicePoolList(query: InvoicePoolListQuery = {}) { return apiRequestData( `/api/invoice-pool${toQueryString(query as Record)}`, ); } export async function fetchInvoicePoolDetail(invoiceId: string) { return apiRequestData(`/api/invoice-pool/${invoiceId}`); } export async function uploadInvoice(file: File, ocrType?: string, ownerEmployeeId?: string) { const formData = new FormData(); formData.append("file", file); if (ocrType) { formData.append("ocr_type", ocrType); } if (ownerEmployeeId) { formData.append("owner_employee_id", ownerEmployeeId); } return apiRequestData<{ invoicePoolId: string; status: string; fileSha256: string }>( "/api/invoice-pool/upload", { method: "POST", body: formData, }, ); } export async function bindInvoice( invoiceId: string, reimbursementIdOrPayload: string | InvoiceBindPayload, linkedItemId?: string, ) { const payload = typeof reimbursementIdOrPayload === "string" ? { reimbursementId: reimbursementIdOrPayload, linkedItemId } : reimbursementIdOrPayload; return apiRequestData>(`/api/invoice-pool/${invoiceId}/bind`, { method: "POST", body: JSON.stringify(payload), }); } export async function fetchInvoiceSignedUrl(invoiceId: string) { return apiRequestData<{ signedUrl: string; expiresAt: string }>( `/api/invoice-pool/${invoiceId}/signed-url`, { method: "POST", body: JSON.stringify({}), }, ); } export type InvoicePatchPayload = Partial<{ status: "available"; remarks: string | null; invoiceCode: string | null; invoiceNumber: string | null; invoiceDate: string | null; sellerName: string | null; buyerName: string | null; amount: string | null; taxAmount: string | null; totalAmount: string | null; }>; export async function patchInvoice(invoiceId: string, payload: InvoicePatchPayload) { return apiRequestData(`/api/invoice-pool/${invoiceId}`, { method: "PATCH", body: JSON.stringify(payload), }); } export async function archiveInvoice(invoiceId: string) { return apiRequestData(`/api/invoice-pool/${invoiceId}/archive`, { method: "POST", body: JSON.stringify({}), }); } export async function unbindInvoice(invoiceId: string) { return apiRequestData(`/api/invoice-pool/${invoiceId}/unbind`, { method: "POST", body: JSON.stringify({}), }); } export async function retryInvoiceOcr(invoiceId: string) { return apiRequestData(`/api/invoice-pool/${invoiceId}/retry-ocr`, { method: "POST", body: JSON.stringify({}), }); } export async function overrideInvoiceDuplicate(invoiceId: string, payload: { refFormNumber: string; reason: string }) { return apiRequestData(`/api/invoice-pool/${invoiceId}/override-duplicate`, { method: "POST", body: JSON.stringify(payload), }); } export async function triggerInvoiceVerification(invoiceId: string) { return apiRequestData<{ invoiceId: string; verificationId: string; provider: string; triggerMode: string }>( `/api/invoice-pool/${invoiceId}/verify`, { method: "POST", body: JSON.stringify({}), }, ); } export async function fetchInvoiceVerifications(invoiceId: string, limit = 20) { return apiRequestData<{ invoiceId: string; items: InvoiceVerificationRecord[] }>( `/api/invoice-pool/${invoiceId}/verification?limit=${limit}`, ); } export async function retryInvoiceVerification(invoiceId: string) { return apiRequestData<{ invoiceId: string; verificationId: string; status: string }>( `/api/invoice-pool/${invoiceId}/verification/retry`, { method: "POST", body: JSON.stringify({}), }, ); }