/** * Suppliers service API implementation * Handles all supplier-related backend communications */ import { apiClient } from '../client/apiClient'; import type { SupplierCreate, SupplierUpdate, SupplierResponse, SupplierSummary, SupplierApproval, SupplierQueryParams, SupplierStatistics, TopSuppliersResponse, PurchaseOrderCreate, PurchaseOrderUpdate, PurchaseOrderResponse, PurchaseOrderApproval, PurchaseOrderQueryParams, DeliveryCreate, DeliveryUpdate, DeliveryResponse, DeliveryReceiptConfirmation, DeliveryQueryParams, PerformanceCalculationRequest, PerformanceMetrics, PerformanceAlert, PaginatedResponse, ApiResponse, } from '../types/suppliers'; class SuppliersService { private readonly baseUrl = '/tenants'; private readonly purchaseOrdersUrl = '/purchase-orders'; private readonly deliveriesUrl = '/deliveries'; private readonly performanceUrl = '/performance'; // Supplier Management async createSupplier( tenantId: string, supplierData: SupplierCreate ): Promise { return apiClient.post( `${this.baseUrl}/${tenantId}/suppliers`, supplierData ); } async getSuppliers( tenantId: string, queryParams?: SupplierQueryParams ): Promise> { 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); if (queryParams?.limit) params.append('limit', queryParams.limit.toString()); if (queryParams?.offset) params.append('offset', queryParams.offset.toString()); if (queryParams?.sort_by) params.append('sort_by', queryParams.sort_by); if (queryParams?.sort_order) params.append('sort_order', queryParams.sort_order); const queryString = params.toString() ? `?${params.toString()}` : ''; return apiClient.get>( `${this.baseUrl}/${tenantId}/suppliers${queryString}` ); } async getSupplier(tenantId: string, supplierId: string): Promise { return apiClient.get( `${this.baseUrl}/${tenantId}/suppliers/${supplierId}` ); } async updateSupplier( tenantId: string, supplierId: string, updateData: SupplierUpdate ): Promise { return apiClient.put( `${this.baseUrl}/${tenantId}/suppliers/${supplierId}`, updateData ); } async deleteSupplier( tenantId: string, supplierId: string ): Promise<{ message: string }> { return apiClient.delete<{ message: string }>( `${this.baseUrl}/${tenantId}/suppliers/${supplierId}` ); } // Specialized Supplier Endpoints async getSupplierStatistics(tenantId: string): Promise { return apiClient.get( `${this.baseUrl}/${tenantId}/suppliers/statistics` ); } async getActiveSuppliers( tenantId: string, queryParams?: Omit ): Promise> { return this.getSuppliers(tenantId, { ...queryParams, status: 'active' }); } async getTopSuppliers(tenantId: string): Promise { return apiClient.get( `${this.baseUrl}/${tenantId}/suppliers/top` ); } async getPendingApprovalSuppliers( tenantId: string ): Promise> { return this.getSuppliers(tenantId, { status: 'pending_approval' }); } async getSuppliersByType( tenantId: string, supplierType: string, queryParams?: Omit ): Promise> { return apiClient.get>( `${this.baseUrl}/${tenantId}/suppliers/types/${supplierType}` ); } // Supplier Approval Workflow async approveSupplier( tenantId: string, supplierId: string, approval: SupplierApproval ): Promise { return apiClient.post( `${this.baseUrl}/${tenantId}/suppliers/${supplierId}/approve`, approval ); } // Purchase Orders async createPurchaseOrder(orderData: PurchaseOrderCreate): Promise { return apiClient.post(this.purchaseOrdersUrl, orderData); } async getPurchaseOrders( queryParams?: PurchaseOrderQueryParams ): Promise> { 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); if (queryParams?.date_from) params.append('date_from', queryParams.date_from); if (queryParams?.date_to) params.append('date_to', queryParams.date_to); if (queryParams?.limit) params.append('limit', queryParams.limit.toString()); if (queryParams?.offset) params.append('offset', queryParams.offset.toString()); if (queryParams?.sort_by) params.append('sort_by', queryParams.sort_by); if (queryParams?.sort_order) params.append('sort_order', queryParams.sort_order); const queryString = params.toString() ? `?${params.toString()}` : ''; return apiClient.get>( `${this.purchaseOrdersUrl}${queryString}` ); } async getPurchaseOrder(orderId: string): Promise { return apiClient.get(`${this.purchaseOrdersUrl}/${orderId}`); } async updatePurchaseOrder( orderId: string, updateData: PurchaseOrderUpdate ): Promise { return apiClient.put( `${this.purchaseOrdersUrl}/${orderId}`, updateData ); } async approvePurchaseOrder( orderId: string, approval: PurchaseOrderApproval ): Promise { return apiClient.post( `${this.purchaseOrdersUrl}/${orderId}/approve`, approval ); } // Deliveries async createDelivery(deliveryData: DeliveryCreate): Promise { return apiClient.post(this.deliveriesUrl, deliveryData); } async getDeliveries( queryParams?: DeliveryQueryParams ): Promise> { 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); } if (queryParams?.status) params.append('status', queryParams.status); if (queryParams?.scheduled_date_from) { params.append('scheduled_date_from', queryParams.scheduled_date_from); } if (queryParams?.scheduled_date_to) { params.append('scheduled_date_to', queryParams.scheduled_date_to); } if (queryParams?.limit) params.append('limit', queryParams.limit.toString()); if (queryParams?.offset) params.append('offset', queryParams.offset.toString()); if (queryParams?.sort_by) params.append('sort_by', queryParams.sort_by); if (queryParams?.sort_order) params.append('sort_order', queryParams.sort_order); const queryString = params.toString() ? `?${params.toString()}` : ''; return apiClient.get>( `${this.deliveriesUrl}${queryString}` ); } async getDelivery(deliveryId: string): Promise { return apiClient.get(`${this.deliveriesUrl}/${deliveryId}`); } async updateDelivery( deliveryId: string, updateData: DeliveryUpdate ): Promise { return apiClient.put( `${this.deliveriesUrl}/${deliveryId}`, updateData ); } async confirmDeliveryReceipt( deliveryId: string, confirmation: DeliveryReceiptConfirmation ): Promise { return apiClient.post( `${this.deliveriesUrl}/${deliveryId}/confirm-receipt`, confirmation ); } // Performance Tracking async calculateSupplierPerformance( tenantId: string, supplierId: string, request?: PerformanceCalculationRequest ): Promise<{ message: string; calculation_id: string }> { const params = new URLSearchParams(); if (request?.period) params.append('period', request.period); if (request?.period_start) params.append('period_start', request.period_start); if (request?.period_end) params.append('period_end', request.period_end); const queryString = params.toString() ? `?${params.toString()}` : ''; return apiClient.post<{ message: string; calculation_id: string }>( `${this.performanceUrl}/tenants/${tenantId}/suppliers/${supplierId}/calculate${queryString}` ); } async getSupplierPerformanceMetrics( tenantId: string, supplierId: string ): Promise { return apiClient.get( `${this.performanceUrl}/tenants/${tenantId}/suppliers/${supplierId}/metrics` ); } async evaluatePerformanceAlerts( tenantId: string ): Promise<{ alerts_generated: number; message: string }> { return apiClient.post<{ alerts_generated: number; message: string }>( `${this.performanceUrl}/tenants/${tenantId}/alerts/evaluate` ); } async getPerformanceAlerts( tenantId: string, supplierId?: string ): Promise { const url = supplierId ? `${this.performanceUrl}/tenants/${tenantId}/suppliers/${supplierId}/alerts` : `${this.performanceUrl}/tenants/${tenantId}/alerts`; return apiClient.get(url); } // Utility methods calculateOrderTotal( items: { ordered_quantity: number; unit_price: number }[], taxAmount: number = 0, shippingCost: number = 0, discountAmount: number = 0 ): number { const subtotal = items.reduce( (sum, item) => sum + (item.ordered_quantity * item.unit_price), 0 ); return subtotal + taxAmount + shippingCost - discountAmount; } formatSupplierCode(name: string, sequence?: number): string { const cleanName = name.replace(/[^a-zA-Z0-9]/g, '').toUpperCase(); const prefix = cleanName.substring(0, 3).padEnd(3, 'X'); const suffix = sequence ? sequence.toString().padStart(3, '0') : '001'; return `${prefix}${suffix}`; } validateTaxId(taxId: string, country: string = 'ES'): boolean { // Simplified validation - real implementation would have proper country-specific validation if (country === 'ES') { // Spanish VAT format: ES + letter + 8 digits or ES + 8 digits + letter const spanishVatRegex = /^ES[A-Z]\d{8}$|^ES\d{8}[A-Z]$/; return spanishVatRegex.test(taxId.toUpperCase()); } return taxId.length > 0; } formatCurrency(amount: number, currency: string = 'EUR'): string { return new Intl.NumberFormat('es-ES', { style: 'currency', currency: currency, }).format(amount); } } // Create and export singleton instance export const suppliersService = new SuppliersService(); export default suppliersService;