Propagated modules: - payment-terminals: MercadoPago + Clip TPV - ai: Role-based AI access (ADMIN, SUPERVISOR_PRODUCCION, OPERADOR_CORTE, OPERADOR_HORNO) - mcp: 18 ERP tools for AI assistants Priority: P2 (industrial clients pay via transfer) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
330 lines
9.5 KiB
TypeScript
330 lines
9.5 KiB
TypeScript
import {
|
|
McpToolProvider,
|
|
McpToolDefinition,
|
|
McpToolHandler,
|
|
McpContext,
|
|
} from '../interfaces';
|
|
|
|
/**
|
|
* Sales Tools Service
|
|
* Provides MCP tools for sales management and reporting.
|
|
* Used by: ADMIN, SUPERVISOR, OPERATOR roles
|
|
*/
|
|
export class SalesToolsService implements McpToolProvider {
|
|
getTools(): McpToolDefinition[] {
|
|
return [
|
|
{
|
|
name: 'get_sales_summary',
|
|
description: 'Obtiene resumen de ventas del dia, semana o mes',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
period: {
|
|
type: 'string',
|
|
enum: ['today', 'week', 'month', 'year'],
|
|
description: 'Periodo del resumen',
|
|
default: 'today',
|
|
},
|
|
branch_id: {
|
|
type: 'string',
|
|
format: 'uuid',
|
|
description: 'Filtrar por sucursal (opcional)',
|
|
},
|
|
},
|
|
},
|
|
returns: {
|
|
type: 'object',
|
|
properties: {
|
|
total_sales: { type: 'number' },
|
|
transaction_count: { type: 'number' },
|
|
average_ticket: { type: 'number' },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: 'get_sales_report',
|
|
description: 'Genera reporte detallado de ventas por rango de fechas',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
start_date: {
|
|
type: 'string',
|
|
format: 'date',
|
|
description: 'Fecha inicial (YYYY-MM-DD)',
|
|
},
|
|
end_date: {
|
|
type: 'string',
|
|
format: 'date',
|
|
description: 'Fecha final (YYYY-MM-DD)',
|
|
},
|
|
group_by: {
|
|
type: 'string',
|
|
enum: ['day', 'week', 'month', 'branch', 'category', 'seller'],
|
|
description: 'Agrupar resultados por',
|
|
default: 'day',
|
|
},
|
|
branch_id: {
|
|
type: 'string',
|
|
format: 'uuid',
|
|
description: 'Filtrar por sucursal',
|
|
},
|
|
},
|
|
required: ['start_date', 'end_date'],
|
|
},
|
|
returns: { type: 'array', items: { type: 'object' } },
|
|
},
|
|
{
|
|
name: 'get_top_products',
|
|
description: 'Obtiene los productos mas vendidos',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
period: {
|
|
type: 'string',
|
|
enum: ['today', 'week', 'month', 'year'],
|
|
default: 'month',
|
|
},
|
|
limit: { type: 'number', default: 10 },
|
|
branch_id: { type: 'string', format: 'uuid' },
|
|
},
|
|
},
|
|
returns: { type: 'array', items: { type: 'object' } },
|
|
},
|
|
{
|
|
name: 'get_top_customers',
|
|
description: 'Obtiene los clientes con mas compras',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
period: {
|
|
type: 'string',
|
|
enum: ['month', 'quarter', 'year'],
|
|
default: 'month',
|
|
},
|
|
limit: { type: 'number', default: 10 },
|
|
order_by: {
|
|
type: 'string',
|
|
enum: ['amount', 'transactions'],
|
|
default: 'amount',
|
|
},
|
|
},
|
|
},
|
|
returns: { type: 'array', items: { type: 'object' } },
|
|
},
|
|
{
|
|
name: 'get_sales_by_branch',
|
|
description: 'Compara ventas entre sucursales',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
period: {
|
|
type: 'string',
|
|
enum: ['today', 'week', 'month'],
|
|
default: 'today',
|
|
},
|
|
},
|
|
},
|
|
returns: { type: 'array', items: { type: 'object' } },
|
|
},
|
|
{
|
|
name: 'get_my_sales',
|
|
description: 'Obtiene las ventas del usuario actual (operador)',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
period: {
|
|
type: 'string',
|
|
enum: ['today', 'week', 'month'],
|
|
default: 'today',
|
|
},
|
|
},
|
|
},
|
|
returns: {
|
|
type: 'object',
|
|
properties: {
|
|
total: { type: 'number' },
|
|
count: { type: 'number' },
|
|
sales: { type: 'array' },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: 'create_sale',
|
|
description: 'Registra una nueva venta',
|
|
category: 'sales',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
items: {
|
|
type: 'array',
|
|
items: {
|
|
type: 'object',
|
|
properties: {
|
|
product_id: { type: 'string', format: 'uuid' },
|
|
quantity: { type: 'number', minimum: 1 },
|
|
unit_price: { type: 'number' },
|
|
discount: { type: 'number', default: 0 },
|
|
},
|
|
required: ['product_id', 'quantity'],
|
|
},
|
|
},
|
|
customer_id: { type: 'string', format: 'uuid' },
|
|
payment_method: {
|
|
type: 'string',
|
|
enum: ['cash', 'card', 'transfer', 'credit'],
|
|
},
|
|
notes: { type: 'string' },
|
|
},
|
|
required: ['items', 'payment_method'],
|
|
},
|
|
returns: {
|
|
type: 'object',
|
|
properties: {
|
|
sale_id: { type: 'string' },
|
|
total: { type: 'number' },
|
|
status: { type: 'string' },
|
|
},
|
|
},
|
|
},
|
|
];
|
|
}
|
|
|
|
getHandler(toolName: string): McpToolHandler | undefined {
|
|
const handlers: Record<string, McpToolHandler> = {
|
|
get_sales_summary: this.getSalesSummary.bind(this),
|
|
get_sales_report: this.getSalesReport.bind(this),
|
|
get_top_products: this.getTopProducts.bind(this),
|
|
get_top_customers: this.getTopCustomers.bind(this),
|
|
get_sales_by_branch: this.getSalesByBranch.bind(this),
|
|
get_my_sales: this.getMySales.bind(this),
|
|
create_sale: this.createSale.bind(this),
|
|
};
|
|
return handlers[toolName];
|
|
}
|
|
|
|
private async getSalesSummary(
|
|
params: { period?: string; branch_id?: string },
|
|
context: McpContext
|
|
): Promise<any> {
|
|
// TODO: Connect to SalesService
|
|
const period = params.period || 'today';
|
|
return {
|
|
period,
|
|
branch_id: params.branch_id || 'all',
|
|
total_sales: 15750.00,
|
|
transaction_count: 42,
|
|
average_ticket: 375.00,
|
|
comparison: {
|
|
previous_period: 14200.00,
|
|
change_percent: 10.9,
|
|
},
|
|
message: 'Conectar a SalesService real',
|
|
};
|
|
}
|
|
|
|
private async getSalesReport(
|
|
params: { start_date: string; end_date: string; group_by?: string; branch_id?: string },
|
|
context: McpContext
|
|
): Promise<any[]> {
|
|
// TODO: Connect to SalesService
|
|
return [
|
|
{
|
|
date: params.start_date,
|
|
total: 5250.00,
|
|
count: 15,
|
|
avg_ticket: 350.00,
|
|
},
|
|
{
|
|
date: params.end_date,
|
|
total: 4800.00,
|
|
count: 12,
|
|
avg_ticket: 400.00,
|
|
},
|
|
];
|
|
}
|
|
|
|
private async getTopProducts(
|
|
params: { period?: string; limit?: number; branch_id?: string },
|
|
context: McpContext
|
|
): Promise<any[]> {
|
|
// TODO: Connect to SalesService
|
|
return [
|
|
{ rank: 1, product: 'Producto A', quantity: 150, revenue: 7500.00 },
|
|
{ rank: 2, product: 'Producto B', quantity: 120, revenue: 6000.00 },
|
|
{ rank: 3, product: 'Producto C', quantity: 100, revenue: 5000.00 },
|
|
].slice(0, params.limit || 10);
|
|
}
|
|
|
|
private async getTopCustomers(
|
|
params: { period?: string; limit?: number; order_by?: string },
|
|
context: McpContext
|
|
): Promise<any[]> {
|
|
// TODO: Connect to CustomersService
|
|
return [
|
|
{ rank: 1, customer: 'Cliente A', total: 25000.00, transactions: 15 },
|
|
{ rank: 2, customer: 'Cliente B', total: 18000.00, transactions: 12 },
|
|
].slice(0, params.limit || 10);
|
|
}
|
|
|
|
private async getSalesByBranch(
|
|
params: { period?: string },
|
|
context: McpContext
|
|
): Promise<any[]> {
|
|
// TODO: Connect to SalesService + BranchesService
|
|
return [
|
|
{ branch: 'Sucursal Centro', total: 8500.00, count: 25 },
|
|
{ branch: 'Sucursal Norte', total: 7250.00, count: 17 },
|
|
];
|
|
}
|
|
|
|
private async getMySales(
|
|
params: { period?: string },
|
|
context: McpContext
|
|
): Promise<any> {
|
|
// TODO: Connect to SalesService with context.userId
|
|
return {
|
|
user_id: context.userId,
|
|
period: params.period || 'today',
|
|
total: 3500.00,
|
|
count: 8,
|
|
sales: [
|
|
{ id: 'sale-1', total: 450.00, time: '10:30' },
|
|
{ id: 'sale-2', total: 680.00, time: '11:45' },
|
|
],
|
|
};
|
|
}
|
|
|
|
private async createSale(
|
|
params: {
|
|
items: Array<{ product_id: string; quantity: number; unit_price?: number; discount?: number }>;
|
|
customer_id?: string;
|
|
payment_method: string;
|
|
notes?: string;
|
|
},
|
|
context: McpContext
|
|
): Promise<any> {
|
|
// TODO: Connect to SalesService
|
|
const total = params.items.reduce((sum, item) => {
|
|
const price = item.unit_price || 100; // Default price for demo
|
|
const discount = item.discount || 0;
|
|
return sum + (price * item.quantity * (1 - discount / 100));
|
|
}, 0);
|
|
|
|
return {
|
|
sale_id: `SALE-${Date.now()}`,
|
|
total,
|
|
items_count: params.items.length,
|
|
payment_method: params.payment_method,
|
|
status: 'completed',
|
|
created_by: context.userId,
|
|
message: 'Conectar a SalesService real',
|
|
};
|
|
}
|
|
}
|