erp-core-frontend-v2/src/services/api/sales.api.ts
rckrdmrd f1a9ea3d1f [TASK-2026-01-20-004] feat: Add API clients for sales, purchases, financial, CRM, projects
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>
2026-01-20 04:06:32 -06:00

275 lines
8.3 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 SalesOrderLine {
id?: string;
productId: string;
productName?: string;
quantity: number;
unitPrice: number;
discount?: number;
taxIds?: string[];
subtotal?: number;
}
export interface SalesOrder extends BaseEntity {
name: string;
partnerId: string;
partnerName?: string;
dateOrder: string;
dateDelivery?: string;
status: 'draft' | 'confirmed' | 'done' | 'cancelled';
pricelistId?: string;
paymentTermId?: string;
warehouseId?: string;
lines: SalesOrderLine[];
amountUntaxed: number;
amountTax: number;
amountTotal: number;
notes?: string;
tenantId: string;
}
export interface Quotation extends BaseEntity {
name: string;
partnerId: string;
partnerName?: string;
dateQuotation: string;
dateExpiry?: string;
status: 'draft' | 'sent' | 'confirmed' | 'cancelled' | 'expired';
pricelistId?: string;
paymentTermId?: string;
lines: SalesOrderLine[];
amountUntaxed: number;
amountTax: number;
amountTotal: number;
notes?: string;
tenantId: string;
}
// ============================================================================
// DTOs
// ============================================================================
export interface CreateSalesOrderDto {
partnerId: string;
dateOrder?: string;
dateDelivery?: string;
pricelistId?: string;
paymentTermId?: string;
warehouseId?: string;
lines: Omit<SalesOrderLine, 'id' | 'productName' | 'subtotal'>[];
notes?: string;
}
export interface UpdateSalesOrderDto {
partnerId?: string;
dateOrder?: string;
dateDelivery?: string;
pricelistId?: string;
paymentTermId?: string;
warehouseId?: string;
lines?: Omit<SalesOrderLine, 'productName' | 'subtotal'>[];
notes?: string;
}
export interface CreateQuotationDto {
partnerId: string;
dateQuotation?: string;
dateExpiry?: string;
pricelistId?: string;
paymentTermId?: string;
lines: Omit<SalesOrderLine, 'id' | 'productName' | 'subtotal'>[];
notes?: string;
}
export interface UpdateQuotationDto {
partnerId?: string;
dateQuotation?: string;
dateExpiry?: string;
pricelistId?: string;
paymentTermId?: string;
lines?: Omit<SalesOrderLine, 'productName' | 'subtotal'>[];
notes?: string;
}
// ============================================================================
// Filters
// ============================================================================
export interface SalesOrderFilters extends PaginationParams {
partnerId?: string;
status?: SalesOrder['status'];
dateFrom?: string;
dateTo?: string;
}
export interface QuotationFilters extends PaginationParams {
partnerId?: string;
status?: Quotation['status'];
dateFrom?: string;
dateTo?: string;
}
// ============================================================================
// API Client
// ============================================================================
export const salesApi = {
// Orders
getOrders: async (filters?: SalesOrderFilters): Promise<PaginatedResponse<SalesOrder>> => {
const response = await api.get<PaginatedResponse<SalesOrder>>(
API_ENDPOINTS.SALES.ORDERS,
{ params: filters }
);
return response.data;
},
getOrderById: async (id: string): Promise<SalesOrder> => {
const response = await api.get<ApiResponse<SalesOrder>>(
`${API_ENDPOINTS.SALES.ORDERS}/${id}`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Orden de venta no encontrada');
}
return response.data.data;
},
createOrder: async (data: CreateSalesOrderDto): Promise<SalesOrder> => {
const response = await api.post<ApiResponse<SalesOrder>>(
API_ENDPOINTS.SALES.ORDERS,
data
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al crear orden de venta');
}
return response.data.data;
},
updateOrder: async (id: string, data: UpdateSalesOrderDto): Promise<SalesOrder> => {
const response = await api.patch<ApiResponse<SalesOrder>>(
`${API_ENDPOINTS.SALES.ORDERS}/${id}`,
data
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al actualizar orden de venta');
}
return response.data.data;
},
confirmOrder: async (id: string): Promise<SalesOrder> => {
const response = await api.post<ApiResponse<SalesOrder>>(
`${API_ENDPOINTS.SALES.ORDERS}/${id}/confirm`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al confirmar orden de venta');
}
return response.data.data;
},
cancelOrder: async (id: string): Promise<SalesOrder> => {
const response = await api.post<ApiResponse<SalesOrder>>(
`${API_ENDPOINTS.SALES.ORDERS}/${id}/cancel`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al cancelar orden de venta');
}
return response.data.data;
},
deleteOrder: async (id: string): Promise<void> => {
const response = await api.delete<ApiResponse>(
`${API_ENDPOINTS.SALES.ORDERS}/${id}`
);
if (!response.data.success) {
throw new Error(response.data.error || 'Error al eliminar orden de venta');
}
},
// Quotations
getQuotations: async (filters?: QuotationFilters): Promise<PaginatedResponse<Quotation>> => {
const response = await api.get<PaginatedResponse<Quotation>>(
API_ENDPOINTS.SALES.QUOTATIONS,
{ params: filters }
);
return response.data;
},
getQuotationById: async (id: string): Promise<Quotation> => {
const response = await api.get<ApiResponse<Quotation>>(
`${API_ENDPOINTS.SALES.QUOTATIONS}/${id}`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Cotizacion no encontrada');
}
return response.data.data;
},
createQuotation: async (data: CreateQuotationDto): Promise<Quotation> => {
const response = await api.post<ApiResponse<Quotation>>(
API_ENDPOINTS.SALES.QUOTATIONS,
data
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al crear cotizacion');
}
return response.data.data;
},
updateQuotation: async (id: string, data: UpdateQuotationDto): Promise<Quotation> => {
const response = await api.patch<ApiResponse<Quotation>>(
`${API_ENDPOINTS.SALES.QUOTATIONS}/${id}`,
data
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al actualizar cotizacion');
}
return response.data.data;
},
confirmQuotation: async (id: string): Promise<SalesOrder> => {
const response = await api.post<ApiResponse<SalesOrder>>(
`${API_ENDPOINTS.SALES.QUOTATIONS}/${id}/confirm`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al confirmar cotizacion');
}
return response.data.data;
},
sendQuotation: async (id: string): Promise<Quotation> => {
const response = await api.post<ApiResponse<Quotation>>(
`${API_ENDPOINTS.SALES.QUOTATIONS}/${id}/send`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al enviar cotizacion');
}
return response.data.data;
},
cancelQuotation: async (id: string): Promise<Quotation> => {
const response = await api.post<ApiResponse<Quotation>>(
`${API_ENDPOINTS.SALES.QUOTATIONS}/${id}/cancel`
);
if (!response.data.success || !response.data.data) {
throw new Error(response.data.error || 'Error al cancelar cotizacion');
}
return response.data.data;
},
deleteQuotation: async (id: string): Promise<void> => {
const response = await api.delete<ApiResponse>(
`${API_ENDPOINTS.SALES.QUOTATIONS}/${id}`
);
if (!response.data.success) {
throw new Error(response.data.error || 'Error al eliminar cotizacion');
}
},
};