REFACTOR ALL APIs

This commit is contained in:
Urtzi Alfaro
2025-10-06 15:27:01 +02:00
parent dc8221bd2f
commit 38fb98bc27
166 changed files with 18454 additions and 13605 deletions

View File

@@ -1,6 +1,16 @@
// ================================================================
// frontend/src/api/services/suppliers.ts
// ================================================================
/**
* Suppliers service API implementation
* Handles all supplier-related backend communications
* Suppliers Service - Complete backend alignment
*
* Backend API structure (3-tier architecture):
* - ATOMIC: suppliers.py, purchase_orders.py, deliveries.py
* - OPERATIONS: supplier_operations.py (approval, statistics, performance)
* - ANALYTICS: analytics.py (performance metrics, alerts)
*
* Last Updated: 2025-10-05
* Status: ✅ Complete - Zero drift with backend
*/
import { apiClient } from '../client/apiClient';
@@ -32,17 +42,18 @@ import type {
class SuppliersService {
private readonly baseUrl = '/tenants';
private readonly purchaseOrdersUrl = '/purchase-orders';
private readonly deliveriesUrl = '/deliveries';
private readonly performanceUrl = '/performance';
// Supplier Management
// ===================================================================
// ATOMIC: Suppliers CRUD
// Backend: services/suppliers/app/api/suppliers.py
// ===================================================================
async createSupplier(
tenantId: string,
supplierData: SupplierCreate
): Promise<SupplierResponse> {
return apiClient.post<SupplierResponse>(
`${this.baseUrl}/${tenantId}/suppliers`,
`${this.baseUrl}/${tenantId}/suppliers/suppliers`,
supplierData
);
}
@@ -52,7 +63,7 @@ class SuppliersService {
queryParams?: SupplierQueryParams
): Promise<PaginatedResponse<SupplierSummary>> {
const params = new URLSearchParams();
if (queryParams?.search_term) params.append('search_term', queryParams.search_term);
if (queryParams?.supplier_type) params.append('supplier_type', queryParams.supplier_type);
if (queryParams?.status) params.append('status', queryParams.status);
@@ -63,13 +74,13 @@ class SuppliersService {
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.get<PaginatedResponse<SupplierSummary>>(
`${this.baseUrl}/${tenantId}/suppliers${queryString}`
`${this.baseUrl}/${tenantId}/suppliers/suppliers${queryString}`
);
}
async getSupplier(tenantId: string, supplierId: string): Promise<SupplierResponse> {
return apiClient.get<SupplierResponse>(
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}`
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}`
);
}
@@ -79,7 +90,7 @@ class SuppliersService {
updateData: SupplierUpdate
): Promise<SupplierResponse> {
return apiClient.put<SupplierResponse>(
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}`,
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}`,
updateData
);
}
@@ -89,68 +100,31 @@ class SuppliersService {
supplierId: string
): Promise<{ message: string }> {
return apiClient.delete<{ message: string }>(
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}`
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}`
);
}
// Specialized Supplier Endpoints
async getSupplierStatistics(tenantId: string): Promise<SupplierStatistics> {
return apiClient.get<SupplierStatistics>(
`${this.baseUrl}/${tenantId}/suppliers/statistics`
);
}
// ===================================================================
// ATOMIC: Purchase Orders CRUD
// Backend: services/suppliers/app/api/purchase_orders.py
// ===================================================================
async getActiveSuppliers(
async createPurchaseOrder(
tenantId: string,
queryParams?: Omit<SupplierQueryParams, 'status'>
): Promise<PaginatedResponse<SupplierSummary>> {
return this.getSuppliers(tenantId, { ...queryParams, status: 'active' });
}
async getTopSuppliers(tenantId: string): Promise<TopSuppliersResponse> {
return apiClient.get<TopSuppliersResponse>(
`${this.baseUrl}/${tenantId}/suppliers/top`
orderData: PurchaseOrderCreate
): Promise<PurchaseOrderResponse> {
return apiClient.post<PurchaseOrderResponse>(
`${this.baseUrl}/${tenantId}/suppliers/purchase-orders`,
orderData
);
}
async getPendingApprovalSuppliers(
tenantId: string
): Promise<PaginatedResponse<SupplierSummary>> {
return this.getSuppliers(tenantId, { status: 'pending_approval' });
}
async getSuppliersByType(
tenantId: string,
supplierType: string,
queryParams?: Omit<SupplierQueryParams, 'supplier_type'>
): Promise<PaginatedResponse<SupplierSummary>> {
return apiClient.get<PaginatedResponse<SupplierSummary>>(
`${this.baseUrl}/${tenantId}/suppliers/types/${supplierType}`
);
}
// Supplier Approval Workflow
async approveSupplier(
tenantId: string,
supplierId: string,
approval: SupplierApproval
): Promise<SupplierResponse> {
return apiClient.post<SupplierResponse>(
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}/approve`,
approval
);
}
// Purchase Orders
async createPurchaseOrder(orderData: PurchaseOrderCreate): Promise<PurchaseOrderResponse> {
return apiClient.post<PurchaseOrderResponse>(this.purchaseOrdersUrl, orderData);
}
async getPurchaseOrders(
tenantId: string,
queryParams?: PurchaseOrderQueryParams
): Promise<PaginatedResponse<PurchaseOrderResponse>> {
const params = new URLSearchParams();
if (queryParams?.supplier_id) params.append('supplier_id', queryParams.supplier_id);
if (queryParams?.status) params.append('status', queryParams.status);
if (queryParams?.priority) params.append('priority', queryParams.priority);
@@ -163,44 +137,59 @@ class SuppliersService {
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.get<PaginatedResponse<PurchaseOrderResponse>>(
`${this.purchaseOrdersUrl}${queryString}`
`${this.baseUrl}/${tenantId}/suppliers/purchase-orders${queryString}`
);
}
async getPurchaseOrder(orderId: string): Promise<PurchaseOrderResponse> {
return apiClient.get<PurchaseOrderResponse>(`${this.purchaseOrdersUrl}/${orderId}`);
async getPurchaseOrder(tenantId: string, orderId: string): Promise<PurchaseOrderResponse> {
return apiClient.get<PurchaseOrderResponse>(
`${this.baseUrl}/${tenantId}/suppliers/purchase-orders/${orderId}`
);
}
async updatePurchaseOrder(
tenantId: string,
orderId: string,
updateData: PurchaseOrderUpdate
): Promise<PurchaseOrderResponse> {
return apiClient.put<PurchaseOrderResponse>(
`${this.purchaseOrdersUrl}/${orderId}`,
`${this.baseUrl}/${tenantId}/suppliers/purchase-orders/${orderId}`,
updateData
);
}
async approvePurchaseOrder(
tenantId: string,
orderId: string,
approval: PurchaseOrderApproval
): Promise<PurchaseOrderResponse> {
return apiClient.post<PurchaseOrderResponse>(
`${this.purchaseOrdersUrl}/${orderId}/approve`,
`${this.baseUrl}/${tenantId}/suppliers/purchase-orders/${orderId}/approve`,
approval
);
}
// Deliveries
async createDelivery(deliveryData: DeliveryCreate): Promise<DeliveryResponse> {
return apiClient.post<DeliveryResponse>(this.deliveriesUrl, deliveryData);
// ===================================================================
// ATOMIC: Deliveries CRUD
// Backend: services/suppliers/app/api/deliveries.py
// ===================================================================
async createDelivery(
tenantId: string,
deliveryData: DeliveryCreate
): Promise<DeliveryResponse> {
return apiClient.post<DeliveryResponse>(
`${this.baseUrl}/${tenantId}/suppliers/deliveries`,
deliveryData
);
}
async getDeliveries(
tenantId: string,
queryParams?: DeliveryQueryParams
): Promise<PaginatedResponse<DeliveryResponse>> {
const params = new URLSearchParams();
if (queryParams?.supplier_id) params.append('supplier_id', queryParams.supplier_id);
if (queryParams?.purchase_order_id) {
params.append('purchase_order_id', queryParams.purchase_order_id);
@@ -219,35 +208,112 @@ class SuppliersService {
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.get<PaginatedResponse<DeliveryResponse>>(
`${this.deliveriesUrl}${queryString}`
`${this.baseUrl}/${tenantId}/suppliers/deliveries${queryString}`
);
}
async getDelivery(deliveryId: string): Promise<DeliveryResponse> {
return apiClient.get<DeliveryResponse>(`${this.deliveriesUrl}/${deliveryId}`);
async getDelivery(tenantId: string, deliveryId: string): Promise<DeliveryResponse> {
return apiClient.get<DeliveryResponse>(
`${this.baseUrl}/${tenantId}/suppliers/deliveries/${deliveryId}`
);
}
async updateDelivery(
tenantId: string,
deliveryId: string,
updateData: DeliveryUpdate
): Promise<DeliveryResponse> {
return apiClient.put<DeliveryResponse>(
`${this.deliveriesUrl}/${deliveryId}`,
`${this.baseUrl}/${tenantId}/suppliers/deliveries/${deliveryId}`,
updateData
);
}
async confirmDeliveryReceipt(
tenantId: string,
deliveryId: string,
confirmation: DeliveryReceiptConfirmation
): Promise<DeliveryResponse> {
return apiClient.post<DeliveryResponse>(
`${this.deliveriesUrl}/${deliveryId}/confirm-receipt`,
`${this.baseUrl}/${tenantId}/suppliers/deliveries/${deliveryId}/confirm-receipt`,
confirmation
);
}
// Performance Tracking
// ===================================================================
// OPERATIONS: Supplier Management
// Backend: services/suppliers/app/api/supplier_operations.py
// ===================================================================
async getSupplierStatistics(tenantId: string): Promise<SupplierStatistics> {
return apiClient.get<SupplierStatistics>(
`${this.baseUrl}/${tenantId}/suppliers/operations/statistics`
);
}
async getActiveSuppliers(
tenantId: string,
queryParams?: Omit<SupplierQueryParams, 'status'>
): Promise<PaginatedResponse<SupplierSummary>> {
const params = new URLSearchParams();
if (queryParams?.search_term) params.append('search_term', queryParams.search_term);
if (queryParams?.supplier_type) params.append('supplier_type', queryParams.supplier_type);
if (queryParams?.limit) params.append('limit', queryParams.limit.toString());
if (queryParams?.offset) params.append('offset', queryParams.offset.toString());
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.get<PaginatedResponse<SupplierSummary>>(
`${this.baseUrl}/${tenantId}/suppliers/operations/active${queryString}`
);
}
async getTopSuppliers(tenantId: string): Promise<TopSuppliersResponse> {
return apiClient.get<TopSuppliersResponse>(
`${this.baseUrl}/${tenantId}/suppliers/operations/top`
);
}
async getPendingApprovalSuppliers(
tenantId: string
): Promise<PaginatedResponse<SupplierSummary>> {
return apiClient.get<PaginatedResponse<SupplierSummary>>(
`${this.baseUrl}/${tenantId}/suppliers/operations/pending-review`
);
}
async getSuppliersByType(
tenantId: string,
supplierType: string,
queryParams?: Omit<SupplierQueryParams, 'supplier_type'>
): Promise<PaginatedResponse<SupplierSummary>> {
const params = new URLSearchParams();
if (queryParams?.search_term) params.append('search_term', queryParams.search_term);
if (queryParams?.status) params.append('status', queryParams.status);
if (queryParams?.limit) params.append('limit', queryParams.limit.toString());
if (queryParams?.offset) params.append('offset', queryParams.offset.toString());
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.get<PaginatedResponse<SupplierSummary>>(
`${this.baseUrl}/${tenantId}/suppliers/types/${supplierType}${queryString}`
);
}
async approveSupplier(
tenantId: string,
supplierId: string,
approval: SupplierApproval
): Promise<SupplierResponse> {
return apiClient.post<SupplierResponse>(
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}/approve`,
approval
);
}
// ===================================================================
// ANALYTICS: Performance Metrics
// Backend: services/suppliers/app/api/analytics.py
// ===================================================================
async calculateSupplierPerformance(
tenantId: string,
supplierId: string,
@@ -260,7 +326,7 @@ class SuppliersService {
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.post<{ message: string; calculation_id: string }>(
`${this.performanceUrl}/tenants/${tenantId}/suppliers/${supplierId}/calculate${queryString}`
`${this.baseUrl}/${tenantId}/suppliers/analytics/performance/${supplierId}/calculate${queryString}`
);
}
@@ -269,7 +335,7 @@ class SuppliersService {
supplierId: string
): Promise<PerformanceMetrics> {
return apiClient.get<PerformanceMetrics>(
`${this.performanceUrl}/tenants/${tenantId}/suppliers/${supplierId}/metrics`
`${this.baseUrl}/${tenantId}/suppliers/analytics/performance/${supplierId}/metrics`
);
}
@@ -277,7 +343,7 @@ class SuppliersService {
tenantId: string
): Promise<{ alerts_generated: number; message: string }> {
return apiClient.post<{ alerts_generated: number; message: string }>(
`${this.performanceUrl}/tenants/${tenantId}/alerts/evaluate`
`${this.baseUrl}/${tenantId}/suppliers/analytics/performance/alerts/evaluate`
);
}
@@ -285,14 +351,17 @@ class SuppliersService {
tenantId: string,
supplierId?: string
): Promise<PerformanceAlert[]> {
const url = supplierId
? `${this.performanceUrl}/tenants/${tenantId}/suppliers/${supplierId}/alerts`
: `${this.performanceUrl}/tenants/${tenantId}/alerts`;
const url = supplierId
? `${this.baseUrl}/${tenantId}/suppliers/analytics/performance/${supplierId}/alerts`
: `${this.baseUrl}/${tenantId}/suppliers/analytics/performance/alerts`;
return apiClient.get<PerformanceAlert[]>(url);
}
// Utility methods
// ===================================================================
// UTILITY METHODS (Client-side helpers)
// ===================================================================
calculateOrderTotal(
items: { ordered_quantity: number; unit_price: number }[],
taxAmount: number = 0,
@@ -333,4 +402,4 @@ class SuppliersService {
// Create and export singleton instance
export const suppliersService = new SuppliersService();
export default suppliersService;
export default suppliersService;