fix issue

This commit is contained in:
Marshal
2026-08-20 18:10:29 +00:00
183 changed files with 14241 additions and 1265 deletions

View File

@@ -192,7 +192,13 @@ import {
type SaveLocomotivePayload,
} from "./locomotives.service";
import { overviewService } from "./overview.service";
import { exportsService } from "./exports.service";
import { reportsService } from "./reports.service";
import type {
ExportCountResult,
ExportDatasetEntry,
ExportParams,
} from "@/types/exports";
import type { ReportCatalogEntry, ReportRunParams, ReportRunResult } from "@/types/reports";
import {
paymentsService,
@@ -3354,6 +3360,18 @@ export const api = {
),
},
exports: {
catalog: endpoint<void, ExportDatasetEntry[]>("exports", "catalog", () =>
exportsService.catalog(),
),
count: endpoint<{ key: string; params: ExportParams }, ExportCountResult>(
"exports",
"count",
({ key, params }) => exportsService.count(key, params),
({ key, params }) => ["exports", key, "count", params],
),
},
reports: {
catalog: endpoint<void, ReportCatalogEntry[]>("reports", "catalog", () =>
reportsService.catalog(),

View File

@@ -509,6 +509,53 @@ export const bookingsService = {
return unwrap(response.data) as Freight.ClearanceCharge[];
},
// ── Additional charges (ad-hoc finance billing) ──
getAdditionalCharges: async (id: string): Promise<Freight.AdditionalCharge[]> => {
const response = await client.get(`/bookings/${id}/additional-charges`);
return unwrap(response.data) as Freight.AdditionalCharge[];
},
/** Finance raises a new charge — 'draft' just saves it, 'send' also issues the invoice and notifies the customer. */
createAdditionalCharge: async (
id: string,
payload: { reason: string; amount: number; currency: string; action: "draft" | "send"; file?: File | null },
): Promise<Freight.AdditionalCharge[]> => {
const form = new FormData();
form.append("reason", payload.reason);
form.append("amount", String(payload.amount));
form.append("currency", payload.currency);
form.append("action", payload.action);
if (payload.file) form.append("file", payload.file);
const response = await client.post(`/bookings/${id}/additional-charges`, form, {
headers: { "Content-Type": "multipart/form-data" },
});
return unwrap(response.data) as Freight.AdditionalCharge[];
},
/** Issues the draft charge's payable invoice and notifies the customer. */
sendAdditionalCharge: async (
id: string,
chargeId: string,
): Promise<Freight.AdditionalCharge[]> => {
const response = await client.post(
`/bookings/${id}/additional-charges/${chargeId}/send`,
);
return unwrap(response.data) as Freight.AdditionalCharge[];
},
/** Withdraws a draft or unpaid additional charge. */
cancelAdditionalCharge: async (
id: string,
chargeId: string,
reason?: string,
): Promise<Freight.AdditionalCharge[]> => {
const response = await client.post(
`/bookings/${id}/additional-charges/${chargeId}/cancel`,
{ reason },
);
return unwrap(response.data) as Freight.AdditionalCharge[];
},
/** GL ET asks Djibouti to name the officer handling the shipment in transit. */
requestTransitAssignee: (id: string, note?: string) =>
postBooking<BookingDetail>(B.CLEARANCE_TRANSIT_ASSIGNEE_REQUEST(id), {

View File

@@ -0,0 +1,42 @@
import { api as client } from "../auth/http";
import { unwrap } from "@/utils/endpoint";
import { URL_CONSTANTS } from "@/constants/URLS";
import type {
ExportCountResult,
ExportDatasetEntry,
ExportFormat,
ExportParams,
} from "@/types/exports";
const E = URL_CONSTANTS.EXPORTS;
export const exportsService = {
catalog: async (): Promise<ExportDatasetEntry[]> => {
const response = await client.get(E.CATALOG);
return unwrap(response.data);
},
/** Exact row count for the current filters, plus the per-format caps. */
count: async (key: string, params: ExportParams): Promise<ExportCountResult> => {
const response = await client.get(E.COUNT(key), { params });
return unwrap(response.data);
},
/**
* Streams the export file as a blob — caller triggers the browser save.
* A failure here arrives with a Blob body, so the catch must use
* `extractDownloadErrorMessage`, not the synchronous decoder.
*/
download: async (
key: string,
format: ExportFormat,
fields: string[],
params: ExportParams,
): Promise<Blob> => {
const response = await client.get(E.DOWNLOAD(key), {
params: { ...params, format, fields: fields.join(",") },
responseType: "blob",
});
return response.data as Blob;
},
};

View File

@@ -0,0 +1,51 @@
import { api as client } from "../auth/http";
import { unwrap } from "@/utils/endpoint";
import { URL_CONSTANTS } from "@/constants/URLS";
import type { ApiResponse } from "@/types/apiResponse";
const BASE = URL_CONSTANTS.OPERATIONS_STANDARDS.BASE;
/**
* The railway's operating standards — the numbers the operations reports
* measure actual performance against. One row, edited here.
*/
export interface OperationsStandards {
id: string;
stationStandardHoursEthiopia: number;
stationStandardHoursDjibouti: number;
cycleStandardHoursContainer: number;
cycleStandardHoursBulkDmp: number;
cycleStandardHoursBulkNagad: number;
cycleStandardHoursBulkBcc: number;
defaultLegStandardHours: number;
delayToleranceMinutes: number;
chargedTonsFull20ft: number;
chargedTonsFull40ft: number;
chargedTonsEmpty20ft: number;
chargedTonsEmpty40ft: number;
chargedTonsPerWagonGeneral: number;
chargedTonsPerWagonPerishable: number;
defaultFullTrainsetWagons: number;
updatedAt?: string;
}
export type OperationsStandardsPatch = Partial<
Omit<OperationsStandards, "id" | "updatedAt">
>;
export const operationsStandardsService = {
get: async (): Promise<OperationsStandards> => {
const response = await client.get<ApiResponse<OperationsStandards>>(BASE);
return unwrap(response.data);
},
update: async (
patch: OperationsStandardsPatch,
): Promise<OperationsStandards> => {
const response = await client.patch<ApiResponse<OperationsStandards>>(
BASE,
patch,
);
return unwrap(response.data);
},
};

View File

@@ -96,6 +96,7 @@ const RESOURCE_BASE: Record<RuleEngineResourceSlug, string> = {
"weight-limit-rules": URL_CONSTANTS.RULE_ENGINE.WEIGHT_LIMIT_RULES,
yards: URL_CONSTANTS.RULE_ENGINE.YARDS,
"yard-distances": URL_CONSTANTS.RULE_ENGINE.YARD_DISTANCES,
"operations-targets": URL_CONSTANTS.RULE_ENGINE.OPERATIONS_TARGETS,
"shipping-lines": URL_CONSTANTS.RULE_ENGINE.SHIPPING_LINES,
rates: URL_CONSTANTS.RULE_ENGINE.RATES,
"approval-rules": URL_CONSTANTS.RULE_ENGINE.APPROVAL_RULES,

View File

@@ -64,6 +64,7 @@ import type {
Warehouse,
WarehouseActivityLog,
WarehouseDashboard,
WarehouseDashboardFilter,
WarehouseFacility,
WarehouseFilter,
WarehouseInventoryItem,
@@ -245,7 +246,10 @@ export const warehouseService = {
apiClient.get<Warehouse[]>(URL_CONSTANTS.WAREHOUSES.BASE, {
params: cleanParams(filter ?? {}),
}),
dashboard: () => apiClient.get<WarehouseDashboard>(URL_CONSTANTS.WAREHOUSES.DASHBOARD),
dashboard: (filter?: WarehouseDashboardFilter) =>
apiClient.get<WarehouseDashboard>(URL_CONSTANTS.WAREHOUSES.DASHBOARD, {
params: cleanParams(filter ?? {}),
}),
getDashboardSummary: (_filter?: InventoryFilter) =>
apiClient.get<WarehouseDashboard>(URL_CONSTANTS.WAREHOUSES.DASHBOARD),
getById: (id: string) => apiClient.get<Warehouse>(URL_CONSTANTS.WAREHOUSES.BY_ID(id)),