Files
edr-platform/apps/edr-freight-web/backoffice/src/services/contract-templates.service.ts
Marshal b926a3116e feat: enhance train scheduling and contract management features
- Added StationWorkControls to manage loading/unloading phases in TrainScheduleV2DetailPage.
- Implemented API endpoints for recording station work and managing wagon detach requests.
- Updated contract templates to include Ethiopian customs handling options.
- Enhanced shipment forms to collect customs clearing agent details for without-customs bookings.
- Introduced NUMBER_OF_WAGONS as a unit of measure for bulk cargo, allowing customers to specify wagon counts.
- Improved validation for customs clearing agent information in shipment forms.
- Updated various components and services to accommodate new features and ensure data integrity.
2026-08-25 21:44:21 +00:00

150 lines
4.1 KiB
TypeScript

import { api as client } from "../auth/http";
const BASE = "/contract-templates";
export const BULK_TEMPLATE_DIRECTIONS = ["IMPORT", "EXPORT", "INTERCITY"] as const;
export type BulkTemplateDirection = (typeof BULK_TEMPLATE_DIRECTIONS)[number];
export interface ContractTemplateArticle {
id: string;
title: string;
body: string;
order: number;
}
export interface ContractTemplate {
id: string;
// System container templates use the fixed DIRECTION_CONTAINER(_CUSTOMS)
// codes; staff-created bulk templates get generated BULK_<cargo>_* codes.
code: string;
name: string;
description?: string | null;
documentTitle: string;
whereasClauses: string[];
articles: ContractTemplateArticle[];
isActive: boolean;
/** Bulk templates only: the cargo type this template is written for. */
cargoTypeId?: string | null;
cargoType?: { id: string; cargoTypeName: string } | null;
/** Bulk templates only: IMPORT, EXPORT or INTERCITY. */
tradeDirection?: BulkTemplateDirection | null;
/**
* Bulk templates only: whether this is the with-customs-clearing variant.
* Null for intercity — domestic movements have no customs leg.
*/
withCustoms?: boolean | null;
/**
* Bulk templates only: the with-customs variant restricted to Ethiopian-side
* clearing (Djibouti stays with the client).
*/
ethiopianCustomsOnly?: boolean | null;
/** The seeded container templates — cannot be deleted. */
isSystem: boolean;
createdAt: string;
updatedAt: string;
}
export interface CreateContractTemplatePayload {
cargoTypeId: string;
tradeDirection: BulkTemplateDirection;
/** Omitted for INTERCITY — the API rejects the flag there. */
withCustoms?: boolean;
/** Ethiopian-side clearing only; requires withCustoms: true. */
ethiopianCustomsOnly?: boolean;
name?: string;
description?: string;
}
export interface UpdateContractTemplatePayload {
name?: string;
description?: string;
documentTitle?: string;
whereasClauses?: string[];
isActive?: boolean;
}
export interface ArticlePayload {
title: string;
body: string;
position?: number;
}
export const contractTemplatesService = {
async list(): Promise<ContractTemplate[]> {
const { data } = await client.get<ContractTemplate[]>(BASE);
return data;
},
async create(payload: CreateContractTemplatePayload): Promise<ContractTemplate> {
const { data } = await client.post<ContractTemplate>(BASE, payload);
return data;
},
async remove(code: string): Promise<void> {
await client.delete(`${BASE}/${code}`);
},
async getByCode(code: string): Promise<ContractTemplate> {
const { data } = await client.get<ContractTemplate>(`${BASE}/${code}`);
return data;
},
async update(
code: string,
payload: UpdateContractTemplatePayload,
): Promise<ContractTemplate> {
const { data } = await client.patch<ContractTemplate>(
`${BASE}/${code}`,
payload,
);
return data;
},
async preview(code: string): Promise<{ html: string }> {
const { data } = await client.post<{ html: string }>(
`${BASE}/${code}/preview`,
{},
);
return data;
},
async addArticle(code: string, payload: ArticlePayload): Promise<ContractTemplate> {
const { data } = await client.post<ContractTemplate>(
`${BASE}/${code}/articles`,
payload,
);
return data;
},
async updateArticle(
code: string,
articleId: string,
payload: Partial<ArticlePayload>,
): Promise<ContractTemplate> {
const { data } = await client.patch<ContractTemplate>(
`${BASE}/${code}/articles/${articleId}`,
payload,
);
return data;
},
async removeArticle(code: string, articleId: string): Promise<ContractTemplate> {
const { data } = await client.delete<ContractTemplate>(
`${BASE}/${code}/articles/${articleId}`,
);
return data;
},
async replaceArticles(
code: string,
articles: Array<{ id?: string; title: string; body: string }>,
): Promise<ContractTemplate> {
const { data } = await client.put<ContractTemplate>(
`${BASE}/${code}/articles`,
{ articles },
);
return data;
},
};