Files
edr-platform/apps/edr-freight-web/backoffice/src/services/procurement.service.ts
Hagernesh 8dc4dd585e feat(procurement): validate acquisition lease fields and enforce bulk-receive capacity
Reject lease start/end and monthly payment on PURCHASE acquisitions (create and
update, validated against the resulting record). Add asset_acquisitions.item_name
column + migration. Enforce warehouse/yard/zone capacity on bulk receive and apply
capacity-counter deltas on save. Adds acquisition-guard spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 12:15:47 +00:00

140 lines
3.9 KiB
TypeScript

import { api } from "@/auth/http";
export type VendorType = "DEALER" | "LEASING" | "PARTS" | "SERVICE" | "OTHER";
export type AcquisitionType = "PURCHASE" | "LEASE" | "RENTAL";
export type AcquisitionStatus = "ACTIVE" | "LEASE_EXPIRING" | "DISPOSED";
export type DisposalMethod = "SALE" | "SCRAP" | "RETURN_LEASE" | "TRADE_IN";
export interface Vendor {
id: string;
name: string;
type?: VendorType | null;
contactPerson?: string | null;
phone?: string | null;
email?: string | null;
address?: string | null;
isActive: boolean;
createdAt: string;
updatedAt: string;
}
export interface AssetAcquisition {
id: string;
itemName?: string | null;
vehicleId?: string | null;
vendorId?: string | null;
acquisitionType: AcquisitionType;
acquisitionDate: string;
cost?: number | null;
usefulLifeMonths?: number | null;
salvageValue?: number | null;
leaseStart?: string | null;
leaseEnd?: string | null;
monthlyPayment?: number | null;
status: AcquisitionStatus;
notes?: string | null;
vehicle?: {
id: string;
plateNumber?: string | null;
registrationNumber?: string | null;
manufacturer?: string | null;
model?: string | null;
} | null;
vendor?: Vendor | null;
createdAt: string;
updatedAt: string;
}
export interface AssetDisposal {
id: string;
vehicleId: string;
disposalDate: string;
method: DisposalMethod;
salePrice?: number | null;
buyer?: string | null;
notes?: string | null;
createdAt: string;
updatedAt: string;
}
export interface DepreciationResult {
method: "STRAIGHT_LINE";
cost: number;
salvageValue: number;
usefulLifeMonths: number;
monthsElapsed: number;
monthlyDepreciation: number;
bookValue: number;
}
export interface LifecycleResult {
vehicleId: string;
acquisition: AssetAcquisition | null;
disposal: AssetDisposal | null;
depreciation: DepreciationResult | null;
}
export interface CreateVendorPayload {
name: string;
type?: VendorType;
contactPerson?: string;
phone?: string;
email?: string;
address?: string;
isActive?: boolean;
}
export interface CreateAcquisitionPayload {
vehicleId?: string;
vendorId?: string;
acquisitionType: AcquisitionType;
acquisitionDate: string;
cost?: number;
usefulLifeMonths?: number;
salvageValue?: number;
leaseStart?: string;
leaseEnd?: string;
monthlyPayment?: number;
status?: AcquisitionStatus;
notes?: string;
}
export interface CreateDisposalPayload {
vehicleId: string;
disposalDate: string;
method: DisposalMethod;
salePrice?: number;
buyer?: string;
notes?: string;
}
export const procurementService = {
// Vendors
listVendors: () => api.get<Vendor[]>("/procurement/vendors"),
createVendor: (data: CreateVendorPayload) => api.post("/procurement/vendors", data),
updateVendor: (id: string, data: Partial<CreateVendorPayload>) =>
api.patch(`/procurement/vendors/${id}`, data),
deleteVendor: (id: string) => api.delete(`/procurement/vendors/${id}`),
// Acquisitions
listAcquisitions: (vehicleId?: string) =>
api.get<AssetAcquisition[]>(
`/procurement/acquisitions${vehicleId ? `?vehicleId=${vehicleId}` : ""}`,
),
getAcquisition: (id: string) => api.get<AssetAcquisition>(`/procurement/acquisitions/${id}`),
createAcquisition: (data: CreateAcquisitionPayload) =>
api.post("/procurement/acquisitions", data),
updateAcquisition: (id: string, data: Partial<CreateAcquisitionPayload>) =>
api.patch(`/procurement/acquisitions/${id}`, data),
deleteAcquisition: (id: string) => api.delete(`/procurement/acquisitions/${id}`),
// Disposals
listDisposals: () => api.get<AssetDisposal[]>("/procurement/disposals"),
createDisposal: (data: CreateDisposalPayload) => api.post("/procurement/disposals", data),
deleteDisposal: (id: string) => api.delete(`/procurement/disposals/${id}`),
// Lifecycle
lifecycle: (vehicleId: string) =>
api.get<LifecycleResult>(`/procurement/lifecycle/${vehicleId}`),
};