EPIC-P1-004: Frontend API clients - Add sales.api.ts (orders, quotations, returns) - Add purchases.api.ts (purchase orders, suppliers, receipts) - Add financial.api.ts (accounts, journals, payments) - Add crm.api.ts (leads, opportunities, campaigns) - Add projects.api.ts (projects, tasks, timesheets) - Update api/index.ts with new exports Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
280 lines
8.8 KiB
TypeScript
280 lines
8.8 KiB
TypeScript
import api from './axios-instance';
|
|
import { API_ENDPOINTS } from '@shared/constants/api-endpoints';
|
|
import type { BaseEntity } from '@shared/types/entities.types';
|
|
import type { ApiResponse, PaginatedResponse, PaginationParams } from '@shared/types/api.types';
|
|
|
|
// ============================================================================
|
|
// Interfaces
|
|
// ============================================================================
|
|
|
|
export interface PurchaseOrderLine {
|
|
id?: string;
|
|
productId: string;
|
|
productName?: string;
|
|
quantity: number;
|
|
unitPrice: number;
|
|
discount?: number;
|
|
taxIds?: string[];
|
|
subtotal?: number;
|
|
dateExpected?: string;
|
|
}
|
|
|
|
export interface PurchaseOrder extends BaseEntity {
|
|
name: string;
|
|
partnerId: string;
|
|
partnerName?: string;
|
|
dateOrder: string;
|
|
dateExpected?: string;
|
|
status: 'draft' | 'confirmed' | 'received' | 'done' | 'cancelled';
|
|
paymentTermId?: string;
|
|
warehouseId?: string;
|
|
lines: PurchaseOrderLine[];
|
|
amountUntaxed: number;
|
|
amountTax: number;
|
|
amountTotal: number;
|
|
notes?: string;
|
|
tenantId: string;
|
|
}
|
|
|
|
export interface PurchaseRfq extends BaseEntity {
|
|
name: string;
|
|
partnerId: string;
|
|
partnerName?: string;
|
|
dateRfq: string;
|
|
dateExpiry?: string;
|
|
status: 'draft' | 'sent' | 'confirmed' | 'cancelled' | 'expired';
|
|
paymentTermId?: string;
|
|
lines: PurchaseOrderLine[];
|
|
amountUntaxed: number;
|
|
amountTax: number;
|
|
amountTotal: number;
|
|
notes?: string;
|
|
tenantId: string;
|
|
}
|
|
|
|
// ============================================================================
|
|
// DTOs
|
|
// ============================================================================
|
|
|
|
export interface CreatePurchaseOrderDto {
|
|
partnerId: string;
|
|
dateOrder?: string;
|
|
dateExpected?: string;
|
|
paymentTermId?: string;
|
|
warehouseId?: string;
|
|
lines: Omit<PurchaseOrderLine, 'id' | 'productName' | 'subtotal'>[];
|
|
notes?: string;
|
|
}
|
|
|
|
export interface UpdatePurchaseOrderDto {
|
|
partnerId?: string;
|
|
dateOrder?: string;
|
|
dateExpected?: string;
|
|
paymentTermId?: string;
|
|
warehouseId?: string;
|
|
lines?: Omit<PurchaseOrderLine, 'productName' | 'subtotal'>[];
|
|
notes?: string;
|
|
}
|
|
|
|
export interface CreatePurchaseRfqDto {
|
|
partnerId: string;
|
|
dateRfq?: string;
|
|
dateExpiry?: string;
|
|
paymentTermId?: string;
|
|
lines: Omit<PurchaseOrderLine, 'id' | 'productName' | 'subtotal'>[];
|
|
notes?: string;
|
|
}
|
|
|
|
export interface UpdatePurchaseRfqDto {
|
|
partnerId?: string;
|
|
dateRfq?: string;
|
|
dateExpiry?: string;
|
|
paymentTermId?: string;
|
|
lines?: Omit<PurchaseOrderLine, 'productName' | 'subtotal'>[];
|
|
notes?: string;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Filters
|
|
// ============================================================================
|
|
|
|
export interface PurchaseOrderFilters extends PaginationParams {
|
|
partnerId?: string;
|
|
status?: PurchaseOrder['status'];
|
|
dateFrom?: string;
|
|
dateTo?: string;
|
|
}
|
|
|
|
export interface PurchaseRfqFilters extends PaginationParams {
|
|
partnerId?: string;
|
|
status?: PurchaseRfq['status'];
|
|
dateFrom?: string;
|
|
dateTo?: string;
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Client
|
|
// ============================================================================
|
|
|
|
export const purchasesApi = {
|
|
// Orders
|
|
getOrders: async (filters?: PurchaseOrderFilters): Promise<PaginatedResponse<PurchaseOrder>> => {
|
|
const response = await api.get<PaginatedResponse<PurchaseOrder>>(
|
|
API_ENDPOINTS.PURCHASES.ORDERS,
|
|
{ params: filters }
|
|
);
|
|
return response.data;
|
|
},
|
|
|
|
getOrderById: async (id: string): Promise<PurchaseOrder> => {
|
|
const response = await api.get<ApiResponse<PurchaseOrder>>(
|
|
`${API_ENDPOINTS.PURCHASES.ORDERS}/${id}`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Orden de compra no encontrada');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
createOrder: async (data: CreatePurchaseOrderDto): Promise<PurchaseOrder> => {
|
|
const response = await api.post<ApiResponse<PurchaseOrder>>(
|
|
API_ENDPOINTS.PURCHASES.ORDERS,
|
|
data
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al crear orden de compra');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
updateOrder: async (id: string, data: UpdatePurchaseOrderDto): Promise<PurchaseOrder> => {
|
|
const response = await api.patch<ApiResponse<PurchaseOrder>>(
|
|
`${API_ENDPOINTS.PURCHASES.ORDERS}/${id}`,
|
|
data
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al actualizar orden de compra');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
confirmOrder: async (id: string): Promise<PurchaseOrder> => {
|
|
const response = await api.post<ApiResponse<PurchaseOrder>>(
|
|
`${API_ENDPOINTS.PURCHASES.ORDERS}/${id}/confirm`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al confirmar orden de compra');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
receiveOrder: async (id: string): Promise<PurchaseOrder> => {
|
|
const response = await api.post<ApiResponse<PurchaseOrder>>(
|
|
`${API_ENDPOINTS.PURCHASES.ORDERS}/${id}/receive`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al recibir orden de compra');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
cancelOrder: async (id: string): Promise<PurchaseOrder> => {
|
|
const response = await api.post<ApiResponse<PurchaseOrder>>(
|
|
`${API_ENDPOINTS.PURCHASES.ORDERS}/${id}/cancel`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al cancelar orden de compra');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
deleteOrder: async (id: string): Promise<void> => {
|
|
const response = await api.delete<ApiResponse>(
|
|
`${API_ENDPOINTS.PURCHASES.ORDERS}/${id}`
|
|
);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al eliminar orden de compra');
|
|
}
|
|
},
|
|
|
|
// RFQs (Request for Quotation)
|
|
getRfqs: async (filters?: PurchaseRfqFilters): Promise<PaginatedResponse<PurchaseRfq>> => {
|
|
const response = await api.get<PaginatedResponse<PurchaseRfq>>(
|
|
API_ENDPOINTS.PURCHASES.RFQS,
|
|
{ params: filters }
|
|
);
|
|
return response.data;
|
|
},
|
|
|
|
getRfqById: async (id: string): Promise<PurchaseRfq> => {
|
|
const response = await api.get<ApiResponse<PurchaseRfq>>(
|
|
`${API_ENDPOINTS.PURCHASES.RFQS}/${id}`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Solicitud de cotizacion no encontrada');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
createRfq: async (data: CreatePurchaseRfqDto): Promise<PurchaseRfq> => {
|
|
const response = await api.post<ApiResponse<PurchaseRfq>>(
|
|
API_ENDPOINTS.PURCHASES.RFQS,
|
|
data
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al crear solicitud de cotizacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
updateRfq: async (id: string, data: UpdatePurchaseRfqDto): Promise<PurchaseRfq> => {
|
|
const response = await api.patch<ApiResponse<PurchaseRfq>>(
|
|
`${API_ENDPOINTS.PURCHASES.RFQS}/${id}`,
|
|
data
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al actualizar solicitud de cotizacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
sendRfq: async (id: string): Promise<PurchaseRfq> => {
|
|
const response = await api.post<ApiResponse<PurchaseRfq>>(
|
|
`${API_ENDPOINTS.PURCHASES.RFQS}/${id}/send`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al enviar solicitud de cotizacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
confirmRfq: async (id: string): Promise<PurchaseOrder> => {
|
|
const response = await api.post<ApiResponse<PurchaseOrder>>(
|
|
`${API_ENDPOINTS.PURCHASES.RFQS}/${id}/confirm`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al confirmar solicitud de cotizacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
cancelRfq: async (id: string): Promise<PurchaseRfq> => {
|
|
const response = await api.post<ApiResponse<PurchaseRfq>>(
|
|
`${API_ENDPOINTS.PURCHASES.RFQS}/${id}/cancel`
|
|
);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al cancelar solicitud de cotizacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
deleteRfq: async (id: string): Promise<void> => {
|
|
const response = await api.delete<ApiResponse>(
|
|
`${API_ENDPOINTS.PURCHASES.RFQS}/${id}`
|
|
);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al eliminar solicitud de cotizacion');
|
|
}
|
|
},
|
|
};
|