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

287 lines 13 kB
import { getTypesenseClient } from "syia-mcp-utils"; import { logger } from "../../index.js"; export class ExportToolHandler { constructor() { this.typesenseClient = getTypesenseClient(); } /** * Convert Unix timestamps to ISO strings for specific date fields */ convertUnixDates(doc) { const dateFields = [ 'purchaseRequisitionDate', 'purchaseOrderIssuedDate', 'orderReadinessDate', 'date', 'poDate', 'expenseDate' ]; const convertedDoc = { ...doc }; dateFields.forEach(field => { if (convertedDoc[field] && typeof convertedDoc[field] === 'number') { // Convert Unix timestamp (seconds) to ISO string convertedDoc[field] = new Date(convertedDoc[field] * 1000).toISOString(); } }); return convertedDoc; } async getCompleteVesselPurchaseRequisitionData(arguments_) { const collection = "purchase"; const imo = arguments_.imo; const start_date = arguments_.start_date; const end_date = arguments_.end_date; if (!imo) { throw new Error("IMO number is required"); } try { // Compose filter_by string from inputs const filterParts = [`imo:${imo}`]; if (start_date) { const startTs = Math.floor(new Date(start_date).getTime() / 1000); filterParts.push(`purchaseRequisitionDate:>=${startTs}`); } if (end_date) { const endTs = Math.floor(new Date(end_date).getTime() / 1000); filterParts.push(`purchaseRequisitionDate:<=${endTs}`); } const filterBy = filterParts.join(" && "); // Build query for export const query = { filter_by: filterBy }; logger.debug(`[Typesense Query] ${JSON.stringify(query)}`); // Use export method to get all documents const exportResult = await this.typesenseClient.collections(collection).documents().export(query); // Debug the export result logger.debug(`Export result type: ${typeof exportResult}`); logger.debug(`Export result length: ${exportResult?.length || 'undefined'}`); logger.debug(`First 200 chars of export result: ${exportResult?.substring(0, 200)}`); // Parse the export result (it's typically JSONL format) const lines = exportResult.split('\n').filter((line) => line.trim()); logger.debug(`Number of lines after split: ${lines.length}`); logger.debug(`First line: ${lines[0]}`); const documents = lines.map((line, index) => { try { const doc = JSON.parse(line); // Remove embedding field and convert dates delete doc.embedding; const convertedDoc = this.convertUnixDates(doc); if (index === 0) { logger.debug(`First converted document keys: ${Object.keys(convertedDoc).join(', ')}`); } return convertedDoc; } catch (error) { logger.error(`Error parsing line ${index}: ${line}`); return {}; } }); if (documents.length === 0) { return [{ type: "text", text: `No purchase requisitions found for vessel with IMO ${imo}.`, title: "No Purchase Requisitions Found", format: "json" }]; } const vesselName = documents[0]?.vesselName || null; const title = `Exported purchase requisitions for IMO ${imo}`; const artifactTitle = `Purchase requisition export artifact for IMO ${imo}`; const linkHeader = `Purchase requisition export for IMO ${imo}`; // Process results for export tool return [{ type: "text", text: JSON.stringify({ summary: { imo: imo, vesselName: vesselName, recordCount: documents.length, exportType: "purchase_requisition_data" }, data: documents }, null, 2), title: title, format: "json" }]; } catch (error) { logger.error(`Error executing purchase requisition export: ${error}`); throw new Error(`Error exporting purchase requisitions: ${error.message}`); } } async getCompleteVesselExpenseData(arguments_) { const collection = "expense"; const imo = arguments_.imo; const start_date = arguments_.start_date; const end_date = arguments_.end_date; const excludeFieldsStr = "_id,docId,fleetId,vesselId,fleetManagerId,technicalSuperintendentId"; if (!imo) { throw new Error("IMO number is required"); } try { // Build filter_by string from inputs const filterParts = [`imo:${imo}`]; if (start_date) { const startTs = Math.floor(new Date(start_date).getTime() / 1000); filterParts.push(`expenseDate:>=${startTs}`); } if (end_date) { const endTs = Math.floor(new Date(end_date).getTime() / 1000); filterParts.push(`expenseDate:<=${endTs}`); } const filterBy = filterParts.join(" && "); // Build query for export const query = { filter_by: filterBy, exclude_fields: excludeFieldsStr }; logger.debug(`[Typesense Query] ${JSON.stringify(query)}`); // Use export method to get all documents const exportResult = await this.typesenseClient.collections(collection).documents().export(query); // Debug the export result logger.debug(`Export result type: ${typeof exportResult}`); logger.debug(`Export result length: ${exportResult?.length || 'undefined'}`); logger.debug(`First 200 chars of export result: ${exportResult?.substring(0, 200)}`); // Parse the export result (it's typically JSONL format) const lines = exportResult.split('\n').filter((line) => line.trim()); logger.debug(`Number of lines after split: ${lines.length}`); logger.debug(`First line: ${lines[0]}`); const documents = lines.map((line, index) => { try { const doc = JSON.parse(line); // Remove embedding field and convert dates delete doc.embedding; const convertedDoc = this.convertUnixDates(doc); if (index === 0) { logger.debug(`First converted document keys: ${Object.keys(convertedDoc).join(', ')}`); } return convertedDoc; } catch (error) { logger.error(`Error parsing line ${index}: ${line}`); return {}; } }); if (documents.length === 0) { return [{ type: "text", text: `No expense records found for vessel with IMO ${imo}.`, title: "No Expense Records Found", format: "json" }]; } const vesselName = documents[0]?.vesselName || null; const title = `Exported expense records for IMO ${imo}`; // Process results for export tool return [{ type: "text", text: JSON.stringify({ summary: { imo: imo, vesselName: vesselName, recordCount: documents.length, exportType: "complete_expense_data" }, data: documents }, null, 2), title: title, format: "json" }]; } catch (error) { logger.error(`Error executing expense export: ${error}`); throw new Error(`Error exporting expense records: ${error.message}`); } } async getCompleteVesselBudgetData(arguments_) { const collection = "budget"; const imo = arguments_.imo; const start_date = arguments_.start_date; const end_date = arguments_.end_date; const excludeFieldsStr = "_id,docId,fleetId,vesselId,fleetManagerId,technicalSuperintendentId"; if (!imo) { throw new Error("IMO number is required"); } try { // Build filter_by string from inputs const filterParts = [`imo:${imo}`]; if (start_date) { const startTs = Math.floor(new Date(start_date).getTime() / 1000); filterParts.push(`date:>=${startTs}`); } if (end_date) { const endTs = Math.floor(new Date(end_date).getTime() / 1000); filterParts.push(`date:<=${endTs}`); } const filterBy = filterParts.join(" && "); // Build query for export const query = { filter_by: filterBy, exclude_fields: excludeFieldsStr }; logger.debug(`[Typesense Query] ${JSON.stringify(query)}`); // Use export method to get all documents const exportResult = await this.typesenseClient.collections(collection).documents().export(query); // Debug the export result logger.debug(`Export result type: ${typeof exportResult}`); logger.debug(`Export result length: ${exportResult?.length || 'undefined'}`); logger.debug(`First 200 chars of export result: ${exportResult?.substring(0, 200)}`); // Parse the export result (it's typically JSONL format) const lines = exportResult.split('\n').filter((line) => line.trim()); logger.debug(`Number of lines after split: ${lines.length}`); logger.debug(`First line: ${lines[0]}`); const documents = lines.map((line, index) => { try { const doc = JSON.parse(line); // Remove embedding field delete doc.embedding; if (index === 0) { logger.debug(`Original document keys before conversion: ${Object.keys(doc).join(', ')}`); } // Convert Unix timestamps to ISO strings const convertedDoc = this.convertUnixDates(doc); if (index === 0) { logger.debug(`Final document keys: ${Object.keys(convertedDoc).join(', ')}`); } return convertedDoc; } catch (error) { logger.error(`Error parsing line ${index}: ${line}`); return {}; } }); if (documents.length === 0) { return [{ type: "text", text: `No budget records found for vessel with IMO ${imo}.`, title: "No Budget Records Found", format: "json" }]; } const vesselName = documents[0]?.vesselName || null; const title = `Exported budget records for IMO ${imo}`; const artifactTitle = `Budget export artifact for IMO ${imo}`; const linkHeader = `Budget export for IMO ${imo}`; // Process results for export tool return [{ type: "text", text: JSON.stringify({ summary: { imo: imo, vesselName: vesselName, recordCount: documents.length, exportType: "complete_budget_data" }, data: documents }, null, 2), title: title, format: "json" }]; } catch (error) { logger.error(`Error executing budget export: ${error}`); throw new Error(`Error exporting budget records: ${error.message}`); } } } //# sourceMappingURL=exportTools.js.map