import { apiRequestData } from "./http"; import type { PrecheckResponse, RiskFlag } from "./feeControl"; export type TravelRequestStatus = "draft" | "reviewing" | "approved" | "rejected"; export type TravelTripType = "domestic" | "international"; export type TravelSegmentRole = "outbound" | "return" | "connection"; export type TravelTransportType = "flight" | "train" | "car" | "bus" | "other"; export type TravelRequestSummary = { id: string; requestNo: string | null; applicantEmployeeId: string; submitterId: string | null; departmentId: string; legalEntityId: string; costCenterId: string; budgetPoolId: string | null; purpose: string; tripType: TravelTripType; startDate: string | null; endDate: string | null; estimatedAmount: string; projectId: string | null; project: { id: string; projectNo: string; name: string; } | null; status: TravelRequestStatus; createdAt: string | null; updatedAt: string | null; applicant: { id: string; employeeNo: string; name: string; } | null; submitter: { id: string; employeeNo: string; name: string; } | null; department: { id: string; name: string; } | null; legalEntity: { id: string; code: string; name: string; } | null; costCenter: { id: string; code: string; name: string; legalEntityId: string; } | null; budgetPool: { id: string; code: string; name: string; } | null; }; export type TravelRequestSegment = { id: string; sortOrder: number; segmentRole: TravelSegmentRole; transportType: TravelTransportType; fromCity: string; toCity: string; departAt: string | null; arriveAt: string | null; createdAt: string | null; updatedAt: string | null; }; export type TravelOrderLink = { id: string; source: string; externalOrderNo: string; employeeId: string; linkedReimbursementId: string | null; travelRequestId: string | null; occurredAt: string | null; amount: string | null; currency: string; status: string; paymentVoucherNo: string | null; paymentDate: string | null; paymentChannel: string | null; paidAt: string | null; paidBy: string | null; createdAt: string | null; updatedAt: string | null; }; export type TravelRequestDetail = TravelRequestSummary & { segments: TravelRequestSegment[]; travelOrders: TravelOrderLink[]; pendingWorkflow: { instanceId: string; currentStatus: string; currentStepId: string; task: { id: string; stepId: string; stepName: string; assigneeId: string | null; assigneeRole: string | null; } | null; } | null; permissions: { canEditDraft: boolean; canSubmit: boolean; canWithdraw: boolean; canManage: boolean; }; riskFlags: RiskFlag[]; }; export type TravelRequestListResponse = { page: number; pageSize: number; total: number; mine: boolean; items: TravelRequestSummary[]; }; export type TravelRequestListQuery = { status?: TravelRequestStatus; mine?: boolean; tripType?: TravelTripType; legalEntityId?: string; costCenterId?: string; page?: number; pageSize?: number; }; export type TravelRequestSegmentPayload = { segmentRole: TravelSegmentRole; transportType: TravelTransportType; fromCity: string; toCity: string; departAt: string; arriveAt: string; }; export type TravelRequestPayload = { purpose: string; tripType: TravelTripType; startDate: string; endDate: string; legalEntityId: string; costCenterId: string; estimatedAmount: string; segments: TravelRequestSegmentPayload[]; }; export type TravelRequestSubmitResponse = { travelRequestId: string; requestNo: string; status: "reviewing"; workflowInstanceId: string; currentTaskId: string; budgetPoolId: string | null; budgetReservation: { applied: boolean; reservedAmount?: string; items?: Array<{ budgetPoolId: string; amount: string }>; }; precheckDecision: "pass" | "warn" | "manual_review"; openedRiskFlagCount: number; }; export type TravelRequestWithdrawResponse = { travelRequestId: string; status: "draft"; outcome: "withdrawn"; workflowInstanceId: string | null; budgetRelease: { applied: boolean; items?: Array<{ budgetPoolId: string; amount: 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, typeof value === "boolean" ? (value ? "1" : "0") : String(value)); } const encoded = params.toString(); return encoded ? `?${encoded}` : ""; } export async function fetchTravelRequests(query: TravelRequestListQuery = {}) { return apiRequestData( `/api/travel-requests${toQueryString(query as Record)}`, ); } export async function createTravelRequest(payload: TravelRequestPayload) { return apiRequestData("/api/travel-requests", { method: "POST", body: JSON.stringify(payload), }); } export async function fetchTravelRequestDetail(travelRequestId: string) { return apiRequestData(`/api/travel-requests/${travelRequestId}`); } export async function updateTravelRequest(travelRequestId: string, payload: Partial) { return apiRequestData(`/api/travel-requests/${travelRequestId}`, { method: "PATCH", body: JSON.stringify(payload), }); } export async function precheckTravelRequest(travelRequestId: string) { return apiRequestData(`/api/travel-requests/${travelRequestId}/precheck`, { method: "POST", body: JSON.stringify({}), }); } export async function submitTravelRequest(travelRequestId: string) { return apiRequestData(`/api/travel-requests/${travelRequestId}/submit`, { method: "POST", body: JSON.stringify({}), }); } export async function withdrawTravelRequest(travelRequestId: string) { return apiRequestData(`/api/travel-requests/${travelRequestId}/withdraw`, { method: "POST", body: JSON.stringify({}), }); } export async function linkTravelRequestProject(travelRequestId: string, projectId: string | null) { return apiRequestData<{ projectId: string | null; project: { id: string; projectNo: string; name: string } | null }>(`/api/travel-requests/${travelRequestId}/link-project`, { method: "POST", body: JSON.stringify({ projectId }), }); }