UNPKG

purchase-mcp-server

Version:

Purchase and budget management server handling requisitions, purchase orders, expenses, budgets, and vendor management with ERP access for data extraction

552 lines 20.2 kB
import { getMongoClient } from "../utils/mongodb.js"; import { getTypesenseClient } from "../utils/typesense.js"; import { config } from "../utils/config.js"; import { logger } from "../utils/logger.js"; import { ObjectId } from "mongodb"; export class PurchaseToolHandler { constructor() { this.typesenseClient = getTypesenseClient(); } async getPurchaseRequisitionDetails(arguments_) { const { requisitionId } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const requisition = await db.collection('purchase_requisitions') .findOne({ _id: new ObjectId(requisitionId) }); if (!requisition) { throw new Error(`Purchase requisition not found: ${requisitionId}`); } return [{ type: "text", text: JSON.stringify(requisition, null, 2) }]; } catch (error) { logger.error('Error getting purchase requisition details:', error); throw error; } } async getPurchaseOrderDetails(arguments_) { const { orderId } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const order = await db.collection('purchase_orders') .findOne({ _id: new ObjectId(orderId) }); if (!order) { throw new Error(`Purchase order not found: ${orderId}`); } return [{ type: "text", text: JSON.stringify(order, null, 2) }]; } catch (error) { logger.error('Error getting purchase order details:', error); throw error; } } async listRequisitionsByStatus(arguments_) { const { status, limit = 10 } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const requisitions = await db.collection('purchase_requisitions') .find({ status }) .sort({ createdAt: -1 }) .limit(limit) .toArray(); return [{ type: "text", text: JSON.stringify(requisitions, null, 2) }]; } catch (error) { logger.error('Error listing requisitions by status:', error); throw error; } } async listPurchaseOrdersByStatus(arguments_) { const { status, limit = 10 } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const orders = await db.collection('purchase_orders') .find({ status }) .sort({ createdAt: -1 }) .limit(limit) .toArray(); return [{ type: "text", text: JSON.stringify(orders, null, 2) }]; } catch (error) { logger.error('Error listing purchase orders by status:', error); throw error; } } async listRequisitionsByTypeAndStage(arguments_) { const { type, stage, limit = 10 } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const requisitions = await db.collection('purchase_requisitions') .find({ type, stage }) .sort({ createdAt: -1 }) .limit(limit) .toArray(); return [{ type: "text", text: JSON.stringify(requisitions, null, 2) }]; } catch (error) { logger.error('Error listing requisitions by type and stage:', error); throw error; } } async listRecentRequisitionsByOrderPriority(arguments_) { const { priority, limit = 10 } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const requisitions = await db.collection('purchase_requisitions') .find({ priority }) .sort({ createdAt: -1 }) .limit(limit) .toArray(); return [{ type: "text", text: JSON.stringify(requisitions, null, 2) }]; } catch (error) { logger.error('Error listing recent requisitions by priority:', error); throw error; } } async listTopExpensesByCategory(arguments_) { const { category, year, limit = 10 } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const expenses = await db.collection('expenses') .aggregate([ { $match: { category, year, status: 'approved' } }, { $group: { _id: "$subcategory", totalAmount: { $sum: "$amount" }, count: { $sum: 1 } } }, { $sort: { totalAmount: -1 } }, { $limit: limit } ]).toArray(); return [{ type: "text", text: JSON.stringify(expenses, null, 2) }]; } catch (error) { logger.error('Error listing top expenses by category:', error); throw error; } } async listCommittedCostExpenses(arguments_) { const { vesselId, year } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const expenses = await db.collection('expenses') .find({ vesselId, year, status: 'committed' }) .sort({ createdAt: -1 }) .toArray(); return [{ type: "text", text: JSON.stringify(expenses, null, 2) }]; } catch (error) { logger.error('Error listing committed cost expenses:', error); throw error; } } async getVesselPurchaseLogTable(arguments_) { const { vesselId, startDate, endDate } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const query = { vesselId }; if (startDate || endDate) { query.createdAt = {}; if (startDate) { query.createdAt.$gte = new Date(startDate); } if (endDate) { query.createdAt.$lte = new Date(endDate); } } const logs = await db.collection('purchase_logs') .find(query) .sort({ createdAt: -1 }) .toArray(); return [{ type: "text", text: JSON.stringify(logs, null, 2) }]; } catch (error) { logger.error('Error getting vessel purchase log table:', error); throw error; } } async listRecentUrgentRequisitions(arguments_) { const { limit = 10 } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); const requisitions = await db.collection('purchase_requisitions') .find({ priority: 'urgent', status: { $in: ['pending', 'in_progress'] } }) .sort({ createdAt: -1 }) .limit(limit) .toArray(); return [{ type: "text", text: JSON.stringify(requisitions, null, 2) }]; } catch (error) { logger.error('Error listing recent urgent requisitions:', error); throw error; } } async getCompleteVesselBudgetData(arguments_) { const { imo, year = new Date().getFullYear() } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); // Get vessel information const vessel = await db.collection('vessels').findOne({ imo }); if (!vessel) { throw new Error(`Vessel not found with IMO: ${imo}`); } // Get budget data const budgetData = await db.collection('budgets') .aggregate([ { $match: { vesselId: vessel._id, year: year } }, { $group: { _id: { category: "$category", group: "$group" }, totalBudget: { $sum: "$budgetAmount" }, totalActual: { $sum: "$actualAmount" }, totalCommitted: { $sum: "$committedAmount" } } }, { $project: { _id: 0, category: "$_id.category", group: "$_id.group", totalBudget: 1, totalActual: 1, totalCommitted: 1, variance: { $subtract: ["$totalBudget", { $add: ["$totalActual", "$totalCommitted"] }] } } }, { $sort: { group: 1, category: 1 } } ]).toArray(); // Get expense breakdown const expenseBreakdown = await db.collection('expenses') .aggregate([ { $match: { vesselId: vessel._id, year: year, status: 'approved' } }, { $group: { _id: { category: "$category", month: { $month: "$date" } }, totalAmount: { $sum: "$amount" }, count: { $sum: 1 } } }, { $project: { _id: 0, category: "$_id.category", month: "$_id.month", totalAmount: 1, count: 1 } }, { $sort: { month: 1, category: 1 } } ]).toArray(); // Get committed costs const committedCosts = await db.collection('purchase_orders') .aggregate([ { $match: { vesselId: vessel._id, year: year, status: { $in: ['committed', 'in_progress'] } } }, { $group: { _id: { category: "$category", month: { $month: "$createdAt" } }, totalAmount: { $sum: "$amount" }, count: { $sum: 1 } } }, { $project: { _id: 0, category: "$_id.category", month: "$_id.month", totalAmount: 1, count: 1 } }, { $sort: { month: 1, category: 1 } } ]).toArray(); // Calculate totals const totalBudget = budgetData.reduce((sum, item) => sum + (item.totalBudget || 0), 0); const totalActual = budgetData.reduce((sum, item) => sum + (item.totalActual || 0), 0); const totalCommitted = budgetData.reduce((sum, item) => sum + (item.totalCommitted || 0), 0); const result = { vessel: { imo: vessel.imo, name: vessel.name }, year, budgetSummary: budgetData, expenseBreakdown, committedCosts, totalBudget, totalActual, totalCommitted }; return [{ type: "text", text: JSON.stringify(result, null, 2) }]; } catch (error) { logger.error('Error getting complete vessel budget data:', error); throw error; } } async getAllVesselPurchaseRequisitions(arguments_) { const { imo, status, startDate, endDate } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); // Get vessel information const vessel = await db.collection('vessels').findOne({ imo }); if (!vessel) { throw new Error(`Vessel not found with IMO: ${imo}`); } // Build query const query = { vesselId: vessel._id }; if (status) { query.status = status; } if (startDate || endDate) { query.createdAt = {}; if (startDate) { query.createdAt.$gte = new Date(startDate); } if (endDate) { query.createdAt.$lte = new Date(endDate); } } // Get purchase requisitions const requisitions = await db.collection('purchase_requisitions') .find(query) .sort({ createdAt: -1 }) .toArray(); // Get related purchase orders for each requisition const requisitionsWithOrders = await Promise.all(requisitions.map(async (req) => { const orders = await db.collection('purchase_orders') .find({ requisitionId: req._id }) .toArray(); return { ...req, purchaseOrders: orders }; })); return [{ type: "text", text: JSON.stringify({ vessel: { imo: vessel.imo, name: vessel.name }, requisitions: requisitionsWithOrders }, null, 2) }]; } catch (error) { logger.error('Error getting vessel purchase requisitions:', error); throw error; } } async getVesselExpenseData(arguments_) { const { imo, year = new Date().getFullYear(), category, group } = arguments_; try { const mongoClient = await getMongoClient(config.mongoUri); const db = mongoClient.db(config.dbName); // Get vessel information const vessel = await db.collection('vessels').findOne({ imo }); if (!vessel) { throw new Error(`Vessel not found with IMO: ${imo}`); } // Build query const query = { vesselId: vessel._id, year: year }; if (category) { query.category = category; } if (group) { query.group = group; } // Get actual expenses const actualExpenses = await db.collection('expenses') .aggregate([ { $match: { ...query, status: 'approved' } }, { $group: { _id: { category: "$category", group: "$group", month: { $month: "$date" } }, totalAmount: { $sum: "$amount" }, count: { $sum: 1 } } }, { $project: { _id: 0, category: "$_id.category", group: "$_id.group", month: "$_id.month", totalAmount: 1, count: 1 } }, { $sort: { month: 1, category: 1 } } ]).toArray(); // Get committed costs const committedCosts = await db.collection('purchase_orders') .aggregate([ { $match: { ...query, status: { $in: ['committed', 'in_progress'] } } }, { $group: { _id: { category: "$category", group: "$group", month: { $month: "$createdAt" } }, totalAmount: { $sum: "$amount" }, count: { $sum: 1 } } }, { $project: { _id: 0, category: "$_id.category", group: "$_id.group", month: "$_id.month", totalAmount: 1, count: 1 } }, { $sort: { month: 1, category: 1 } } ]).toArray(); // Calculate totals const totalActual = actualExpenses.reduce((sum, item) => sum + (item.totalAmount || 0), 0); const totalCommitted = committedCosts.reduce((sum, item) => sum + (item.totalAmount || 0), 0); return [{ type: "text", text: JSON.stringify({ vessel: { imo: vessel.imo, name: vessel.name }, year, actualExpenses, committedCosts, totals: { actual: totalActual, committed: totalCommitted, total: totalActual + totalCommitted } }, null, 2) }]; } catch (error) { logger.error('Error getting vessel expense data:', error); throw error; } } } //# sourceMappingURL=purchaseTools.js.map