import { apiRequestData } from "./http"; export type ErpMasterDataResourceType = "legal_entity" | "cost_center" | "supplier"; export type ErpGateStatus = { envEnabled: boolean; effectiveEnabled: boolean; effectiveReason: string; provider: string; masterDataEndpointConfigured: boolean; journalEndpointConfigured: boolean; masterDataSyncCron: string | null; }; export type ErpMasterDataSyncSummary = { requested: number; created: number; updated: number; archived: number; skipped: number; sampleSkipped: Array<{ key: string; reason: string }>; }; export type ErpMasterDataSyncItem = { resourceType: ErpMasterDataResourceType; status: string; lastStartedAt: string | null; lastFinishedAt: string | null; lastSuccessAt: string | null; lastError: string | null; lastResult: ErpMasterDataSyncSummary | null; }; export type ErpMasterDataStatusResponse = { gate: ErpGateStatus; items: ErpMasterDataSyncItem[]; triggerMode?: string; }; export type ReimbursementJournalPreview = { journal: { journalType: string; sourceEventName: string; entityType: string; entityId: string; documentNo: string | null; currencyCode: string; totalAmount: string | null; occurredAt: string | null; paymentVoucherNo: string | null; paymentDate: string | null; dimensions: { departmentId: string | null; ownerEmployeeId: string | null; submitterEmployeeId: string | null; legalEntityCode: string | null; costCenterCode: string | null; }; }; exportState: { externalId: string | null; lastOutboxId: string | null; lastOutboxStatus: string | null; lastError: string | null; exportedAt: string | null; }; }; export type IntegrationOutboxStatus = | "pending" | "processing" | "succeeded" | "failed" | "dead_letter"; export type IntegrationOutboxPayloadSummary = { entityType: string | null; entityId: string | null; sourceEventName: string | null; journalType: string | null; exportType: string | null; identityCode: string | null; }; export type IntegrationOutboxItem = { id: string; eventType: string; status: IntegrationOutboxStatus | string; payloadSummary: IntegrationOutboxPayloadSummary; attempts: number; maxAttempts: number; nextRetryAt: string | null; createdAt: string | null; processedAt: string | null; deadLetterAt: string | null; }; export type IntegrationOutboxDetail = IntegrationOutboxItem & { payload: Record | null; lastError: string | null; }; export type IntegrationOutboxListResponse = { page: number; pageSize: number; total: number; items: IntegrationOutboxItem[]; }; export type IntegrationOutboxStats = { pending: number; processing: number; succeeded: number; failed: number; deadLetter: number; }; export type IntegrationOutboxQuery = { page?: number; pageSize?: number; status?: IntegrationOutboxStatus; eventType?: string; }; export type IntegrationBindingItem = { id: string; provider: string; entityType: string; localId: string; externalId: string | null; externalCode: string | null; lastSyncedAt: string | null; routePath: string | null; }; export type IntegrationBindingListResponse = { page: number; pageSize: number; total: number; items: IntegrationBindingItem[]; }; export type IntegrationBindingQuery = { page?: number; pageSize?: number; provider?: string; entityType?: 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 triggerErpSync(reimbursementId: string, runNow = true) { return apiRequestData<{ outboxId: string; status: string; duplicated: boolean; }>(`/api/integrations/erp/sync/${reimbursementId}?runNow=${runNow ? "1" : "0"}`, { method: "POST", body: JSON.stringify({}), }); } export async function fetchErpMasterDataStatus() { return apiRequestData("/api/integrations/erp/master-data/status"); } export async function syncErpMasterData(payload: { resources?: ErpMasterDataResourceType[] }) { return apiRequestData("/api/integrations/erp/master-data/sync", { method: "POST", body: JSON.stringify(payload), }); } export async function previewReimbursementJournal(reimbursementId: string) { return apiRequestData( `/api/integrations/erp/journals/reimbursements/${reimbursementId}/preview`, ); } export async function exportReimbursementJournal(reimbursementId: string, runNow = true) { return apiRequestData<{ outboxId: string; status: string; duplicated: boolean; requeued: boolean; eventType: string; }>(`/api/integrations/erp/journals/reimbursements/${reimbursementId}/export?runNow=${runNow ? "1" : "0"}`, { method: "POST", body: JSON.stringify({}), }); } export async function fetchIntegrationOutbox(query: IntegrationOutboxQuery = {}) { return apiRequestData( `/api/integrations/outbox${toQueryString({ page: query.page, pageSize: query.pageSize, status: query.status, event_type: query.eventType, })}`, ); } export async function fetchIntegrationOutboxDetail(outboxId: string) { const response = await apiRequestData<{ item: IntegrationOutboxDetail }>(`/api/integrations/outbox/${outboxId}`); return response.item; } export async function retryIntegrationOutbox(outboxId: string) { const response = await apiRequestData<{ item: IntegrationOutboxDetail }>(`/api/integrations/outbox/${outboxId}/retry`, { method: "POST", body: JSON.stringify({}), }); return response.item; } export async function fetchIntegrationOutboxStats() { return apiRequestData("/api/integrations/outbox/stats"); } export async function fetchIntegrationBindings(query: IntegrationBindingQuery = {}) { return apiRequestData( `/api/integrations/bindings${toQueryString({ page: query.page, pageSize: query.pageSize, provider: query.provider, entity_type: query.entityType, })}`, ); } export async function importTravelOrders(payload: { orders: Array<{ source: string; externalOrderNo: string; employeeId: string; linkedReimbursementId?: string; occurredAt?: string; amount?: number; currency?: string; }>; }) { return apiRequestData<{ requested: number; imported: number; skipped: Array<{ source: string; externalOrderNo: string; reason: string }>; items: Array<{ id: string; source: string; externalOrderNo: string; employeeId: string; linkedReimbursementId: string | null; }>; }>(`/api/travel/orders/import`, { method: "POST", body: JSON.stringify(payload), }); } export async function testNotificationChannel(payload: { channelType: string; name: string; }) { return apiRequestData<{ channel: { id: string; channelType: string; name: string; enabled: boolean; }; testResult: { ok: boolean; code: string; response?: Record; }; }>(`/api/notifications/channels/test`, { method: "POST", body: JSON.stringify(payload), }); }