72 lines
4.2 KiB
TypeScript
72 lines
4.2 KiB
TypeScript
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
|||
|
|
|
||
|
|
export interface PlanningCargo {
|
||
|
|
sourceKey: string
|
||
|
|
orderId: string
|
||
|
|
customerId: string
|
||
|
|
customerName: string | null
|
||
|
|
inboundCode: string | null
|
||
|
|
containerBookingId: string
|
||
|
|
containerNo: string | null
|
||
|
|
originWarehouseId: string
|
||
|
|
originWarehouseCode: string
|
||
|
|
originWarehouseName: string
|
||
|
|
destinationWarehouseCode: string
|
||
|
|
packages: number | null
|
||
|
|
receivedPackages: number | null
|
||
|
|
shippedPackages: number | null
|
||
|
|
sourcePalletCount: number | null
|
||
|
|
volumeCbm: number | null
|
||
|
|
estimatedArrivalAt: string | null
|
||
|
|
estimatedWarehouseAt: string | null
|
||
|
|
orderVersion: number
|
||
|
|
standardNode: string
|
||
|
|
shippingVersion: string | null
|
||
|
|
shippingObservedAt: string | null
|
||
|
|
shippingProvider: string | null
|
||
|
|
hasInboundPlan: boolean
|
||
|
|
hasActiveAppointment: boolean
|
||
|
|
detained: boolean
|
||
|
|
mixedDestinations: boolean
|
||
|
|
}
|
||
|
|
export interface PlanningCargoPage { records: PlanningCargo[]; page: number; size: number; total: number; pages: number }
|
||
|
|
export async function listPlanningCargo(query: { page: number; size: number; keyword?: string }, signal?: AbortSignal) {
|
||
|
|
const response = await http.get<ApiEnvelope<PlanningCargoPage>, ApiEnvelope<PlanningCargoPage>>(
|
||
|
|
'/platform/v1/last-leg/appointment-planning/cargo', { params: query, signal },
|
||
|
|
)
|
||
|
|
const page = unwrapApiResponse(response)
|
||
|
|
return { ...page, page: Number(page.page), size: Number(page.size), total: Number(page.total), pages: Number(page.pages) }
|
||
|
|
}
|
||
|
|
|
||
|
|
export type FollowupStage = 'DRAYAGE_CONTACT' | 'TERMINAL_APPOINTMENT' | 'WAREHOUSE_RECEIVING' | 'FBA_RECEIVING'
|
||
|
|
export interface FollowupRecord { stage: FollowupStage; version: number; contactedParty: string | null; result: string; nextAction: string | null; followupDate: string | null; operatorName: string | null; createdAt: string }
|
||
|
|
export interface FollowupHistory { history: { records: FollowupRecord[]; page: number; size: number; total: number; pages: number }; versions: Record<FollowupStage, number> }
|
||
|
|
export interface SaveFollowup { stage: FollowupStage; expectedVersion: number; idempotencyKey: string; contactedParty?: string; result: string; nextAction?: string; followupDate: string | null }
|
||
|
|
export async function getFollowups(sourceKey: string, customerId: string, page: number, size: number) {
|
||
|
|
const result = unwrapApiResponse(await http.get<ApiEnvelope<FollowupHistory>, ApiEnvelope<FollowupHistory>>(
|
||
|
|
`/platform/v1/last-leg/appointment-planning/sources/${encodeURIComponent(sourceKey)}/follow-ups`, { params: { customerId, page, size } },
|
||
|
|
))
|
||
|
|
return { ...result, history: { ...result.history, total: Number(result.history.total) }, versions: Object.fromEntries(Object.entries(result.versions).map(([stage, version]) => [stage, Number(version)])) as Record<FollowupStage, number> }
|
||
|
|
}
|
||
|
|
export async function saveFollowup(sourceKey: string, customerId: string, body: SaveFollowup) {
|
||
|
|
return unwrapApiResponse(await http.post<ApiEnvelope<FollowupRecord>, ApiEnvelope<FollowupRecord>>(
|
||
|
|
`/platform/v1/last-leg/appointment-planning/sources/${encodeURIComponent(sourceKey)}/follow-ups`, body, { params: { customerId } },
|
||
|
|
))
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface PlanningSource {
|
||
|
|
sourceKey: string; customerId: string; orderId: string | null; inboundCode: string | null; bookingNo: string | null;
|
||
|
|
containerNo: string | null; originWarehouseId: string; originWarehouseName: string; destinationKey: string;
|
||
|
|
destinationWarehouseCode: string; packages: number | null; sourceVersion: string | null; canFollowup: boolean; blockReasons: string[];
|
||
|
|
}
|
||
|
|
export interface AppointmentCoverage {
|
||
|
|
status: string; missingFields: string[]; changeReviewRequired: boolean;
|
||
|
|
appointments: Array<{ appointmentNo: string; confirmationNo: string | null; status: string; confirmedAt: string | null; confirmedEndAt: string | null; timezone: string | null }>;
|
||
|
|
}
|
||
|
|
export interface ResolvedPlanningSource { source: PlanningSource; coverage: AppointmentCoverage }
|
||
|
|
export async function resolvePlanningSource(query: { sourceKey: string; customerId: string; destinationKey?: string }) {
|
||
|
|
return unwrapApiResponse(await http.get<ApiEnvelope<ResolvedPlanningSource>, ApiEnvelope<ResolvedPlanningSource>>(
|
||
|
|
'/platform/v1/last-leg/appointment-planning/sources/resolve', { params: query },
|
||
|
|
))
|
||
|
|
}
|