diff --git a/src/modules/mcp/mcp.module.ts b/src/modules/mcp/mcp.module.ts index 453911f..8b651b7 100644 --- a/src/modules/mcp/mcp.module.ts +++ b/src/modules/mcp/mcp.module.ts @@ -9,6 +9,9 @@ import { OrdersToolsService, CustomersToolsService, FiadosToolsService, + SalesToolsService, + FinancialToolsService, + BranchToolsService, } from './tools'; export interface McpModuleOptions { @@ -48,6 +51,9 @@ export class McpModule { this.toolRegistry.registerProvider(new OrdersToolsService()); this.toolRegistry.registerProvider(new CustomersToolsService()); this.toolRegistry.registerProvider(new FiadosToolsService()); + this.toolRegistry.registerProvider(new SalesToolsService()); + this.toolRegistry.registerProvider(new FinancialToolsService()); + this.toolRegistry.registerProvider(new BranchToolsService()); // MCP Server Service this.mcpService = new McpServerService(this.toolRegistry, toolLogger); diff --git a/src/modules/mcp/tools/branch-tools.service.ts b/src/modules/mcp/tools/branch-tools.service.ts new file mode 100644 index 0000000..d352893 --- /dev/null +++ b/src/modules/mcp/tools/branch-tools.service.ts @@ -0,0 +1,292 @@ +import { + McpToolProvider, + McpToolDefinition, + McpToolHandler, + McpContext, +} from '../interfaces'; + +/** + * Branch Tools Service + * Provides MCP tools for branch management and team operations. + * Used by: ADMIN, SUPERVISOR roles + */ +export class BranchToolsService implements McpToolProvider { + getTools(): McpToolDefinition[] { + return [ + { + name: 'get_branch_info', + description: 'Obtiene informacion de una sucursal', + category: 'branches', + parameters: { + type: 'object', + properties: { + branch_id: { + type: 'string', + format: 'uuid', + description: 'ID de la sucursal (usa la actual si no se especifica)', + }, + }, + }, + returns: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + address: { type: 'string' }, + phone: { type: 'string' }, + operating_hours: { type: 'object' }, + }, + }, + }, + { + name: 'get_branch_report', + description: 'Genera reporte de desempeno de sucursal', + category: 'branches', + parameters: { + type: 'object', + properties: { + branch_id: { type: 'string', format: 'uuid' }, + period: { + type: 'string', + enum: ['today', 'week', 'month'], + default: 'today', + }, + }, + }, + returns: { type: 'object' }, + }, + { + name: 'get_team_performance', + description: 'Obtiene metricas de desempeno del equipo', + category: 'branches', + parameters: { + type: 'object', + properties: { + branch_id: { type: 'string', format: 'uuid' }, + period: { + type: 'string', + enum: ['today', 'week', 'month'], + default: 'today', + }, + }, + }, + returns: { + type: 'object', + properties: { + team_size: { type: 'number' }, + members: { type: 'array' }, + }, + }, + }, + { + name: 'get_employee_schedule', + description: 'Obtiene horarios de empleados', + category: 'branches', + parameters: { + type: 'object', + properties: { + branch_id: { type: 'string', format: 'uuid' }, + date: { type: 'string', format: 'date' }, + employee_id: { type: 'string', format: 'uuid' }, + }, + }, + returns: { type: 'array', items: { type: 'object' } }, + }, + { + name: 'get_branch_hours', + description: 'Obtiene horarios de atencion de la sucursal', + category: 'branches', + parameters: { + type: 'object', + properties: { + branch_id: { type: 'string', format: 'uuid' }, + }, + }, + returns: { + type: 'object', + properties: { + regular: { type: 'object' }, + holidays: { type: 'array' }, + }, + }, + }, + { + name: 'get_promotions', + description: 'Obtiene promociones activas', + category: 'branches', + parameters: { + type: 'object', + properties: { + branch_id: { type: 'string', format: 'uuid' }, + active_only: { type: 'boolean', default: true }, + }, + }, + returns: { type: 'array', items: { type: 'object' } }, + }, + ]; + } + + getHandler(toolName: string): McpToolHandler | undefined { + const handlers: Record = { + get_branch_info: this.getBranchInfo.bind(this), + get_branch_report: this.getBranchReport.bind(this), + get_team_performance: this.getTeamPerformance.bind(this), + get_employee_schedule: this.getEmployeeSchedule.bind(this), + get_branch_hours: this.getBranchHours.bind(this), + get_promotions: this.getPromotions.bind(this), + }; + return handlers[toolName]; + } + + private async getBranchInfo( + params: { branch_id?: string }, + context: McpContext + ): Promise { + // TODO: Connect to BranchesService + const branchId = params.branch_id || context.branchId; + return { + id: branchId, + name: 'Sucursal Centro', + code: 'SUC-001', + type: 'store', + address: { + street: 'Av. Principal 123', + city: 'Ciudad de Mexico', + state: 'CDMX', + postal_code: '06600', + }, + phone: '+52 55 1234 5678', + email: 'centro@erp.com', + manager: { + id: 'mgr-001', + name: 'Juan Perez', + }, + operating_hours: { + monday: { open: '09:00', close: '20:00' }, + tuesday: { open: '09:00', close: '20:00' }, + wednesday: { open: '09:00', close: '20:00' }, + thursday: { open: '09:00', close: '20:00' }, + friday: { open: '09:00', close: '20:00' }, + saturday: { open: '10:00', close: '18:00' }, + sunday: { open: 'closed', close: 'closed' }, + }, + message: 'Conectar a BranchesService real', + }; + } + + private async getBranchReport( + params: { branch_id?: string; period?: string }, + context: McpContext + ): Promise { + // TODO: Connect to ReportsService + return { + branch_id: params.branch_id || context.branchId, + period: params.period || 'today', + sales: { + total: 15750.00, + count: 42, + avg_ticket: 375.00, + }, + inventory: { + value: 250000.00, + low_stock_items: 5, + out_of_stock: 2, + }, + staff: { + present: 8, + absent: 1, + late: 0, + }, + goals: { + sales_target: 20000.00, + progress: 78.75, + }, + message: 'Conectar a ReportsService real', + }; + } + + private async getTeamPerformance( + params: { branch_id?: string; period?: string }, + context: McpContext + ): Promise { + // TODO: Connect to HRService + SalesService + return { + branch_id: params.branch_id || context.branchId, + period: params.period || 'today', + team_size: 8, + members: [ + { name: 'Ana Garcia', role: 'Vendedor', sales: 4500.00, transactions: 12, avg_ticket: 375.00 }, + { name: 'Carlos Lopez', role: 'Vendedor', sales: 3800.00, transactions: 10, avg_ticket: 380.00 }, + { name: 'Maria Rodriguez', role: 'Cajero', sales: 2500.00, transactions: 8, avg_ticket: 312.50 }, + ], + top_performer: 'Ana Garcia', + message: 'Conectar a HRService real', + }; + } + + private async getEmployeeSchedule( + params: { branch_id?: string; date?: string; employee_id?: string }, + context: McpContext + ): Promise { + // TODO: Connect to ScheduleService + const date = params.date || new Date().toISOString().split('T')[0]; + return [ + { employee: 'Ana Garcia', shift: 'morning', start: '09:00', end: '15:00', status: 'confirmed' }, + { employee: 'Carlos Lopez', shift: 'afternoon', start: '15:00', end: '21:00', status: 'confirmed' }, + { employee: 'Maria Rodriguez', shift: 'morning', start: '09:00', end: '15:00', status: 'confirmed' }, + ]; + } + + private async getBranchHours( + params: { branch_id?: string }, + context: McpContext + ): Promise { + // TODO: Connect to BranchesService + return { + regular: { + monday: { open: '09:00', close: '20:00' }, + tuesday: { open: '09:00', close: '20:00' }, + wednesday: { open: '09:00', close: '20:00' }, + thursday: { open: '09:00', close: '20:00' }, + friday: { open: '09:00', close: '20:00' }, + saturday: { open: '10:00', close: '18:00' }, + sunday: 'Cerrado', + }, + holidays: [ + { date: '2026-01-01', name: 'Año Nuevo', status: 'closed' }, + { date: '2026-02-03', name: 'Dia de la Constitucion', status: 'closed' }, + ], + next_closed: '2026-02-03', + message: 'Conectar a BranchesService real', + }; + } + + private async getPromotions( + params: { branch_id?: string; active_only?: boolean }, + context: McpContext + ): Promise { + // TODO: Connect to PromotionsService + return [ + { + id: 'promo-001', + name: '2x1 en productos seleccionados', + type: 'bogo', + discount: 50, + start_date: '2026-01-20', + end_date: '2026-01-31', + status: 'active', + applicable_products: ['category:electronics'], + }, + { + id: 'promo-002', + name: '10% descuento con tarjeta', + type: 'percentage', + discount: 10, + start_date: '2026-01-01', + end_date: '2026-03-31', + status: 'active', + conditions: ['payment_method:card'], + }, + ]; + } +} diff --git a/src/modules/mcp/tools/financial-tools.service.ts b/src/modules/mcp/tools/financial-tools.service.ts new file mode 100644 index 0000000..50b2ba8 --- /dev/null +++ b/src/modules/mcp/tools/financial-tools.service.ts @@ -0,0 +1,291 @@ +import { + McpToolProvider, + McpToolDefinition, + McpToolHandler, + McpContext, +} from '../interfaces'; + +/** + * Financial Tools Service + * Provides MCP tools for financial reporting and analysis. + * Used by: ADMIN role only + */ +export class FinancialToolsService implements McpToolProvider { + getTools(): McpToolDefinition[] { + return [ + { + name: 'get_financial_report', + description: 'Genera reporte financiero (ingresos, gastos, utilidad)', + category: 'financial', + parameters: { + type: 'object', + properties: { + type: { + type: 'string', + enum: ['income', 'expenses', 'profit', 'summary'], + description: 'Tipo de reporte', + default: 'summary', + }, + start_date: { + type: 'string', + format: 'date', + description: 'Fecha inicial', + }, + end_date: { + type: 'string', + format: 'date', + description: 'Fecha final', + }, + branch_id: { + type: 'string', + format: 'uuid', + description: 'Filtrar por sucursal', + }, + }, + required: ['type'], + }, + returns: { type: 'object' }, + }, + { + name: 'get_accounts_receivable', + description: 'Obtiene cuentas por cobrar (clientes que deben)', + category: 'financial', + parameters: { + type: 'object', + properties: { + status: { + type: 'string', + enum: ['all', 'current', 'overdue'], + default: 'all', + }, + min_amount: { type: 'number' }, + limit: { type: 'number', default: 50 }, + }, + }, + returns: { + type: 'object', + properties: { + total: { type: 'number' }, + count: { type: 'number' }, + accounts: { type: 'array' }, + }, + }, + }, + { + name: 'get_accounts_payable', + description: 'Obtiene cuentas por pagar (deudas a proveedores)', + category: 'financial', + parameters: { + type: 'object', + properties: { + status: { + type: 'string', + enum: ['all', 'current', 'overdue'], + default: 'all', + }, + due_date_before: { type: 'string', format: 'date' }, + limit: { type: 'number', default: 50 }, + }, + }, + returns: { + type: 'object', + properties: { + total: { type: 'number' }, + count: { type: 'number' }, + accounts: { type: 'array' }, + }, + }, + }, + { + name: 'get_cash_flow', + description: 'Analiza flujo de caja (entradas y salidas)', + category: 'financial', + parameters: { + type: 'object', + properties: { + period: { + type: 'string', + enum: ['week', 'month', 'quarter'], + default: 'month', + }, + branch_id: { type: 'string', format: 'uuid' }, + }, + }, + returns: { + type: 'object', + properties: { + inflows: { type: 'number' }, + outflows: { type: 'number' }, + net_flow: { type: 'number' }, + by_category: { type: 'array' }, + }, + }, + }, + { + name: 'get_kpis', + description: 'Obtiene indicadores clave de desempeno (KPIs)', + category: 'financial', + parameters: { + type: 'object', + properties: { + period: { + type: 'string', + enum: ['month', 'quarter', 'year'], + default: 'month', + }, + }, + }, + returns: { + type: 'object', + properties: { + gross_margin: { type: 'number' }, + net_margin: { type: 'number' }, + inventory_turnover: { type: 'number' }, + avg_collection_days: { type: 'number' }, + }, + }, + }, + ]; + } + + getHandler(toolName: string): McpToolHandler | undefined { + const handlers: Record = { + get_financial_report: this.getFinancialReport.bind(this), + get_accounts_receivable: this.getAccountsReceivable.bind(this), + get_accounts_payable: this.getAccountsPayable.bind(this), + get_cash_flow: this.getCashFlow.bind(this), + get_kpis: this.getKPIs.bind(this), + }; + return handlers[toolName]; + } + + private async getFinancialReport( + params: { type: string; start_date?: string; end_date?: string; branch_id?: string }, + context: McpContext + ): Promise { + // TODO: Connect to FinancialService + return { + type: params.type, + period: { + start: params.start_date || new Date().toISOString().split('T')[0], + end: params.end_date || new Date().toISOString().split('T')[0], + }, + income: 125000.00, + expenses: 85000.00, + gross_profit: 40000.00, + net_profit: 32000.00, + breakdown: { + sales: 120000.00, + services: 5000.00, + cost_of_goods: 65000.00, + operating_expenses: 20000.00, + taxes: 8000.00, + }, + message: 'Conectar a FinancialService real', + }; + } + + private async getAccountsReceivable( + params: { status?: string; min_amount?: number; limit?: number }, + context: McpContext + ): Promise { + // TODO: Connect to AccountsService + return { + total: 45000.00, + count: 12, + overdue_total: 15000.00, + overdue_count: 4, + accounts: [ + { + customer: 'Cliente A', + amount: 5000.00, + due_date: '2026-01-20', + days_overdue: 5, + status: 'overdue', + }, + { + customer: 'Cliente B', + amount: 8000.00, + due_date: '2026-02-01', + days_overdue: 0, + status: 'current', + }, + ].slice(0, params.limit || 50), + message: 'Conectar a AccountsService real', + }; + } + + private async getAccountsPayable( + params: { status?: string; due_date_before?: string; limit?: number }, + context: McpContext + ): Promise { + // TODO: Connect to AccountsService + return { + total: 32000.00, + count: 8, + overdue_total: 5000.00, + overdue_count: 2, + accounts: [ + { + supplier: 'Proveedor X', + amount: 12000.00, + due_date: '2026-01-28', + status: 'current', + }, + { + supplier: 'Proveedor Y', + amount: 5000.00, + due_date: '2026-01-15', + days_overdue: 10, + status: 'overdue', + }, + ].slice(0, params.limit || 50), + message: 'Conectar a AccountsService real', + }; + } + + private async getCashFlow( + params: { period?: string; branch_id?: string }, + context: McpContext + ): Promise { + // TODO: Connect to FinancialService + return { + period: params.period || 'month', + inflows: 95000.00, + outflows: 72000.00, + net_flow: 23000.00, + opening_balance: 45000.00, + closing_balance: 68000.00, + by_category: [ + { category: 'Ventas', type: 'inflow', amount: 90000.00 }, + { category: 'Cobranzas', type: 'inflow', amount: 5000.00 }, + { category: 'Compras', type: 'outflow', amount: 55000.00 }, + { category: 'Nomina', type: 'outflow', amount: 12000.00 }, + { category: 'Gastos operativos', type: 'outflow', amount: 5000.00 }, + ], + message: 'Conectar a FinancialService real', + }; + } + + private async getKPIs( + params: { period?: string }, + context: McpContext + ): Promise { + // TODO: Connect to AnalyticsService + return { + period: params.period || 'month', + gross_margin: 32.5, + net_margin: 18.2, + inventory_turnover: 4.5, + avg_collection_days: 28, + current_ratio: 1.8, + quick_ratio: 1.2, + return_on_assets: 12.5, + trends: { + gross_margin_change: 2.1, + net_margin_change: 1.5, + }, + message: 'Conectar a AnalyticsService real', + }; + } +} diff --git a/src/modules/mcp/tools/index.ts b/src/modules/mcp/tools/index.ts index 795912b..53c814c 100644 --- a/src/modules/mcp/tools/index.ts +++ b/src/modules/mcp/tools/index.ts @@ -3,3 +3,6 @@ export { InventoryToolsService } from './inventory-tools.service'; export { OrdersToolsService } from './orders-tools.service'; export { CustomersToolsService } from './customers-tools.service'; export { FiadosToolsService } from './fiados-tools.service'; +export { SalesToolsService } from './sales-tools.service'; +export { FinancialToolsService } from './financial-tools.service'; +export { BranchToolsService } from './branch-tools.service'; diff --git a/src/modules/mcp/tools/sales-tools.service.ts b/src/modules/mcp/tools/sales-tools.service.ts new file mode 100644 index 0000000..d65ceb9 --- /dev/null +++ b/src/modules/mcp/tools/sales-tools.service.ts @@ -0,0 +1,329 @@ +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 = { + 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 { + // 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 { + // 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 { + // 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 { + // 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 { + // 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 { + // 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 { + // 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', + }; + } +}