Files
bakery-ia/frontend/src/api/services/purchase_orders.ts

346 lines
8.1 KiB
TypeScript

/**
* Purchase Orders API Client
* Handles all API calls for purchase orders
*
* UPDATED in Sprint 3: Purchase orders now managed by Procurement Service
* Previously: Suppliers Service (/tenants/{id}/purchase-orders)
* Now: Procurement Service (/tenants/{id}/procurement/purchase-orders)
*/
import { apiClient } from '../client';
export type PurchaseOrderStatus =
| 'DRAFT'
| 'PENDING_APPROVAL'
| 'APPROVED'
| 'SENT_TO_SUPPLIER'
| 'CONFIRMED'
| 'RECEIVED'
| 'COMPLETED'
| 'CANCELLED'
| 'DISPUTED';
export type PurchaseOrderPriority = 'urgent' | 'high' | 'normal' | 'low';
export interface PurchaseOrderItem {
id: string;
inventory_product_id: string;
product_code?: string;
product_name?: string;
ordered_quantity: number;
unit_of_measure: string;
unit_price: string; // Decimal as string
line_total: string; // Decimal as string
received_quantity: number;
remaining_quantity: number;
quality_requirements?: string;
item_notes?: string;
}
export interface SupplierSummary {
id: string;
name: string;
supplier_code: string;
supplier_type: string;
status: string;
contact_person?: string;
email?: string;
phone?: string;
}
export interface PurchaseOrderSummary {
id: string;
po_number: string;
supplier_id: string;
supplier_name?: string;
status: PurchaseOrderStatus;
priority: PurchaseOrderPriority;
order_date: string;
required_delivery_date?: string;
total_amount: string; // Decimal as string
currency: string;
created_at: string;
reasoning_data?: any; // AI reasoning data for dashboard display
ai_reasoning_summary?: string; // Human-readable summary
}
export interface PurchaseOrderDetail extends PurchaseOrderSummary {
reference_number?: string;
estimated_delivery_date?: string;
// Financial information
subtotal: string;
tax_amount: string;
shipping_cost: string;
discount_amount: string;
// Delivery information
delivery_address?: string;
delivery_instructions?: string;
delivery_contact?: string;
delivery_phone?: string;
// Approval workflow
requires_approval: boolean;
approved_by?: string;
approved_at?: string;
rejection_reason?: string;
// Communication tracking
sent_to_supplier_at?: string;
supplier_confirmation_date?: string;
supplier_reference?: string;
// Additional information
notes?: string;
internal_notes?: string;
terms_and_conditions?: string;
// Audit fields
updated_at: string;
created_by: string;
updated_by: string;
// Related data
supplier?: SupplierSummary;
items?: PurchaseOrderItem[];
}
export interface PurchaseOrderSearchParams {
supplier_id?: string;
status?: PurchaseOrderStatus;
priority?: PurchaseOrderPriority;
date_from?: string; // YYYY-MM-DD
date_to?: string; // YYYY-MM-DD
search_term?: string;
limit?: number;
skip?: number; // ✅ Changed from "offset" to "skip" to match backend
}
export interface PurchaseOrderUpdateData {
status?: PurchaseOrderStatus;
priority?: PurchaseOrderPriority;
notes?: string;
rejection_reason?: string;
internal_notes?: string;
}
export interface PurchaseOrderItemCreate {
inventory_product_id: string;
ordered_quantity: number;
unit_price: string; // Decimal as string
unit_of_measure: string;
quality_requirements?: string;
item_notes?: string;
}
export interface PurchaseOrderCreateData {
supplier_id: string;
required_delivery_date?: string;
priority?: PurchaseOrderPriority;
tax_amount?: number;
shipping_cost?: number;
discount_amount?: number;
notes?: string;
procurement_plan_id?: string;
items: PurchaseOrderItemCreate[];
}
/**
* Create a new purchase order
*/
export async function createPurchaseOrder(
tenantId: string,
data: PurchaseOrderCreateData
): Promise<PurchaseOrderDetail> {
return apiClient.post<PurchaseOrderDetail>(
`/tenants/${tenantId}/procurement/purchase-orders`,
data
);
}
/**
* Get list of purchase orders with optional filters
*/
export async function listPurchaseOrders(
tenantId: string,
params?: PurchaseOrderSearchParams
): Promise<PurchaseOrderSummary[]> {
return apiClient.get<PurchaseOrderSummary[]>(
`/tenants/${tenantId}/procurement/purchase-orders`,
{ params }
);
}
/**
* Get purchase orders by status
*/
export async function getPurchaseOrdersByStatus(
tenantId: string,
status: PurchaseOrderStatus,
limit: number = 50
): Promise<PurchaseOrderSummary[]> {
return listPurchaseOrders(tenantId, { status, limit });
}
/**
* Get pending approval purchase orders
*/
export async function getPendingApprovalPurchaseOrders(
tenantId: string,
limit: number = 50
): Promise<PurchaseOrderSummary[]> {
return getPurchaseOrdersByStatus(tenantId, 'PENDING_APPROVAL', limit);
}
/**
* Get a single purchase order by ID with full details
*/
export async function getPurchaseOrder(
tenantId: string,
poId: string
): Promise<PurchaseOrderDetail> {
return apiClient.get<PurchaseOrderDetail>(
`/tenants/${tenantId}/procurement/purchase-orders/${poId}`
);
}
/**
* Update purchase order
*/
export async function updatePurchaseOrder(
tenantId: string,
poId: string,
data: PurchaseOrderUpdateData
): Promise<PurchaseOrderDetail> {
return apiClient.put<PurchaseOrderDetail>(
`/tenants/${tenantId}/procurement/purchase-orders/${poId}`,
data
);
}
/**
* Approve a purchase order
*/
export async function approvePurchaseOrder(
tenantId: string,
poId: string,
notes?: string
): Promise<PurchaseOrderDetail> {
return apiClient.post<PurchaseOrderDetail>(
`/tenants/${tenantId}/procurement/purchase-orders/${poId}/approve`,
{
action: 'approve',
notes: notes || 'Approved from dashboard'
}
);
}
/**
* Reject a purchase order
*/
export async function rejectPurchaseOrder(
tenantId: string,
poId: string,
reason: string
): Promise<PurchaseOrderDetail> {
return apiClient.post<PurchaseOrderDetail>(
`/tenants/${tenantId}/procurement/purchase-orders/${poId}/approve`,
{
action: 'reject',
notes: reason
}
);
}
/**
* Bulk approve purchase orders
*/
export async function bulkApprovePurchaseOrders(
tenantId: string,
poIds: string[],
notes?: string
): Promise<PurchaseOrderDetail[]> {
const approvalPromises = poIds.map(poId =>
approvePurchaseOrder(tenantId, poId, notes)
);
return Promise.all(approvalPromises);
}
/**
* Delete purchase order
*/
export async function deletePurchaseOrder(
tenantId: string,
poId: string
): Promise<{ message: string }> {
return apiClient.delete<{ message: string }>(
`/tenants/${tenantId}/procurement/purchase-orders/${poId}`
);
}
// ================================================================
// DELIVERY TYPES AND METHODS
// ================================================================
export interface DeliveryItemInput {
purchase_order_item_id: string;
inventory_product_id: string;
ordered_quantity: number;
delivered_quantity: number;
accepted_quantity: number;
rejected_quantity: number;
batch_lot_number?: string;
expiry_date?: string;
quality_grade?: string;
quality_issues?: string;
rejection_reason?: string;
item_notes?: string;
}
export interface CreateDeliveryInput {
purchase_order_id: string;
supplier_id: string;
supplier_delivery_note?: string;
scheduled_date?: string;
estimated_arrival?: string;
carrier_name?: string;
tracking_number?: string;
inspection_passed?: boolean;
inspection_notes?: string;
notes?: string;
items: DeliveryItemInput[];
}
export interface DeliveryResponse {
id: string;
tenant_id: string;
purchase_order_id: string;
supplier_id: string;
delivery_number: string;
status: string;
scheduled_date?: string;
estimated_arrival?: string;
actual_arrival?: string;
completed_at?: string;
inspection_passed?: boolean;
inspection_notes?: string;
notes?: string;
created_at: string;
updated_at: string;
}
/**
* Create delivery for purchase order
*/
export async function createDelivery(
tenantId: string,
poId: string,
deliveryData: CreateDeliveryInput
): Promise<DeliveryResponse> {
return apiClient.post<DeliveryResponse>(
`/tenants/${tenantId}/procurement/purchase-orders/${poId}/deliveries`,
deliveryData
);
}