UNPKG

sap-b1-mcp-server

Version:

SAP Business One Service Layer MCP Server

1,030 lines 44.6 kB
import { z } from 'zod'; // Common schemas const documentQuerySchema = z.object({ filter: z.string().optional().describe('OData $filter expression'), select: z.string().optional().describe('OData $select expression to specify fields'), orderby: z.string().optional().describe('OData $orderby expression'), top: z.number().optional().describe('Maximum number of records to return'), skip: z.number().optional().describe('Number of records to skip for pagination'), expand: z.string().optional().describe('OData $expand expression to include related data') }); // Sales Order Line schema const salesOrderLineSchema = z.object({ ItemCode: z.string().optional().describe('Item code'), ItemDescription: z.string().optional().describe('Item description'), Quantity: z.number().describe('Quantity'), Price: z.number().optional().describe('Unit price'), DiscountPercent: z.number().optional().describe('Discount percentage'), WarehouseCode: z.string().optional().describe('Warehouse code'), VatGroup: z.string().optional().describe('VAT group code'), AccountCode: z.string().optional().describe('G/L account code'), FreeText: z.string().optional().describe('Free text'), ShipDate: z.string().optional().describe('Ship date (YYYY-MM-DD format)'), RequiredDate: z.string().optional().describe('Required date (YYYY-MM-DD format)') }); // Sales Order schema const createSalesOrderSchema = z.object({ CardCode: z.string().describe('Business partner code (customer)'), DocDate: z.string().optional().describe('Document date (YYYY-MM-DD format)'), DocDueDate: z.string().optional().describe('Document due date (YYYY-MM-DD format)'), TaxDate: z.string().optional().describe('Tax date (YYYY-MM-DD format)'), NumAtCard: z.string().optional().describe('Customer reference number'), Comments: z.string().optional().describe('Comments'), Reference1: z.string().optional().describe('Reference 1'), Reference2: z.string().optional().describe('Reference 2'), SalesPersonCode: z.number().optional().describe('Sales person code'), DocCurrency: z.string().optional().describe('Document currency'), ShipToCode: z.string().optional().describe('Ship to address code'), PaymentGroupCode: z.number().optional().describe('Payment terms group code'), DiscountPercent: z.number().optional().describe('Document discount percentage'), DocumentLines: z.array(salesOrderLineSchema).describe('Order lines') }); // Purchase Order Line schema const purchaseOrderLineSchema = z.object({ ItemCode: z.string().optional().describe('Item code'), ItemDescription: z.string().optional().describe('Item description'), Quantity: z.number().describe('Quantity'), Price: z.number().optional().describe('Unit price'), DiscountPercent: z.number().optional().describe('Discount percentage'), WarehouseCode: z.string().optional().describe('Warehouse code'), VatGroup: z.string().optional().describe('VAT group code'), AccountCode: z.string().optional().describe('G/L account code'), FreeText: z.string().optional().describe('Free text'), ShipDate: z.string().optional().describe('Ship date (YYYY-MM-DD format)'), RequiredDate: z.string().optional().describe('Required date (YYYY-MM-DD format)') }); // Purchase Order schema const createPurchaseOrderSchema = z.object({ CardCode: z.string().describe('Business partner code (vendor)'), DocDate: z.string().optional().describe('Document date (YYYY-MM-DD format)'), DocDueDate: z.string().optional().describe('Document due date (YYYY-MM-DD format)'), TaxDate: z.string().optional().describe('Tax date (YYYY-MM-DD format)'), NumAtCard: z.string().optional().describe('Vendor reference number'), Comments: z.string().optional().describe('Comments'), Reference1: z.string().optional().describe('Reference 1'), Reference2: z.string().optional().describe('Reference 2'), SalesPersonCode: z.number().optional().describe('Sales person code'), DocCurrency: z.string().optional().describe('Document currency'), ShipToCode: z.string().optional().describe('Ship to address code'), PaymentGroupCode: z.number().optional().describe('Payment terms group code'), DiscountPercent: z.number().optional().describe('Document discount percentage'), DocumentLines: z.array(purchaseOrderLineSchema).describe('Purchase order lines') }); // Invoice Line schema const invoiceLineSchema = z.object({ ItemCode: z.string().optional().describe('Item code'), ItemDescription: z.string().optional().describe('Item description'), Quantity: z.number().describe('Quantity'), Price: z.number().optional().describe('Unit price'), DiscountPercent: z.number().optional().describe('Discount percentage'), WarehouseCode: z.string().optional().describe('Warehouse code'), VatGroup: z.string().optional().describe('VAT group code'), AccountCode: z.string().optional().describe('G/L account code'), BaseType: z.number().optional().describe('Base document type (17 for Sales Orders)'), BaseEntry: z.number().optional().describe('Base document entry'), BaseLine: z.number().optional().describe('Base document line'), FreeText: z.string().optional().describe('Free text') }); // Invoice schema const createInvoiceSchema = z.object({ CardCode: z.string().describe('Business partner code (customer)'), DocDate: z.string().optional().describe('Document date (YYYY-MM-DD format)'), DocDueDate: z.string().optional().describe('Document due date (YYYY-MM-DD format)'), TaxDate: z.string().optional().describe('Tax date (YYYY-MM-DD format)'), NumAtCard: z.string().optional().describe('Customer reference number'), Comments: z.string().optional().describe('Comments'), Reference1: z.string().optional().describe('Reference 1'), Reference2: z.string().optional().describe('Reference 2'), SalesPersonCode: z.number().optional().describe('Sales person code'), DocCurrency: z.string().optional().describe('Document currency'), ShipToCode: z.string().optional().describe('Ship to address code'), PaymentGroupCode: z.number().optional().describe('Payment terms group code'), DiscountPercent: z.number().optional().describe('Document discount percentage'), DocumentLines: z.array(invoiceLineSchema).describe('Invoice lines') }); // Schema for single order getter const getOrderSchema = z.object({ docEntry: z.number().optional().describe('Document entry number (DocEntry) - internal system ID'), docNum: z.number().optional().describe('Document number (DocNum) - user-visible document number'), select: z.string().optional().describe('OData $select expression to specify fields'), expand: z.string().optional().describe('OData $expand expression to include related data (e.g., "DocumentLines")') }).refine((data) => data.docEntry || data.docNum, { message: "Either docEntry or docNum must be provided" }); // Schema for single purchase order getter const getPurchaseOrderSchema = z.object({ docEntry: z.number().optional().describe('Document entry number (DocEntry) - internal system ID'), docNum: z.number().optional().describe('Document number (DocNum) - user-visible document number'), select: z.string().optional().describe('OData $select expression to specify fields'), expand: z.string().optional().describe('OData $expand expression to include related data (e.g., "DocumentLines")') }).refine((data) => data.docEntry || data.docNum, { message: "Either docEntry or docNum must be provided" }); // Schema for single goods receipt getter const getGoodsReceiptSchema = z.object({ docEntry: z.number().optional().describe('Document entry number (DocEntry) - internal system ID'), docNum: z.number().optional().describe('Document number (DocNum) - user-visible document number'), select: z.string().optional().describe('OData $select expression to specify fields'), expand: z.string().optional().describe('OData $expand expression to include related data (e.g., "DocumentLines")') }).refine((data) => data.docEntry || data.docNum, { message: "Either docEntry or docNum must be provided" }); // Schema for single invoice getter const getInvoiceSchema = z.object({ docEntry: z.number().optional().describe('Document entry number (DocEntry) - internal system ID'), docNum: z.number().optional().describe('Document number (DocNum) - user-visible document number'), select: z.string().optional().describe('OData $select expression to specify fields'), expand: z.string().optional().describe('OData $expand expression to include related data (e.g., "DocumentLines")') }).refine((data) => data.docEntry || data.docNum, { message: "Either docEntry or docNum must be provided" }); export const documentTools = [ { name: 'sap_get_orders', description: 'Retrieve sales orders from SAP Business One with optional filtering, selection, and pagination. Server limit: 20 records maximum per request. Use skip/top for pagination.', inputSchema: { type: 'object', properties: { filter: { type: 'string', description: 'OData $filter expression (e.g., "CardCode eq \'C20000\'" or "DocDate ge \'2024-01-01\'")' }, select: { type: 'string', description: 'OData $select expression to specify fields (e.g., "DocEntry,DocNum,CardCode,CardName,DocTotal")' }, orderby: { type: 'string', description: 'OData $orderby expression (e.g., "DocDate desc" or "DocTotal asc")' }, top: { type: 'number', description: 'Maximum number of records to return (server limit: 20, use 20 for best performance)' }, skip: { type: 'number', description: 'Number of records to skip for pagination (0-based, e.g., skip=20 for page 2, skip=40 for page 3)' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_get_order', description: 'Retrieve a single sales order by DocEntry or DocNum from SAP Business One.', inputSchema: { type: 'object', properties: { docEntry: { type: 'number', description: 'Document entry number (DocEntry) - internal system ID' }, docNum: { type: 'number', description: 'Document number (DocNum) - user-visible document number' }, select: { type: 'string', description: 'OData $select expression to specify fields' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_create_order', description: 'Create a new sales order in SAP Business One.', inputSchema: { type: 'object', properties: { CardCode: { type: 'string', description: 'Business partner code (customer)' }, DocDate: { type: 'string', description: 'Document date (YYYY-MM-DD format)' }, DocDueDate: { type: 'string', description: 'Document due date (YYYY-MM-DD format)' }, TaxDate: { type: 'string', description: 'Tax date (YYYY-MM-DD format)' }, NumAtCard: { type: 'string', description: 'Customer reference number' }, Comments: { type: 'string', description: 'Comments' }, Reference1: { type: 'string', description: 'Reference 1' }, Reference2: { type: 'string', description: 'Reference 2' }, SalesPersonCode: { type: 'number', description: 'Sales person code' }, DocCurrency: { type: 'string', description: 'Document currency' }, ShipToCode: { type: 'string', description: 'Ship to address code' }, PaymentGroupCode: { type: 'number', description: 'Payment terms group code' }, DiscountPercent: { type: 'number', description: 'Document discount percentage' }, DocumentLines: { type: 'array', items: { type: 'object', properties: { ItemCode: { type: 'string', description: 'Item code' }, ItemDescription: { type: 'string', description: 'Item description' }, Quantity: { type: 'number', description: 'Quantity' }, Price: { type: 'number', description: 'Unit price' }, DiscountPercent: { type: 'number', description: 'Discount percentage' }, WarehouseCode: { type: 'string', description: 'Warehouse code' }, VatGroup: { type: 'string', description: 'VAT group code' }, AccountCode: { type: 'string', description: 'G/L account code' }, FreeText: { type: 'string', description: 'Free text' }, ShipDate: { type: 'string', description: 'Ship date (YYYY-MM-DD format)' }, RequiredDate: { type: 'string', description: 'Required date (YYYY-MM-DD format)' } }, required: ['Quantity'] }, description: 'Order lines' } }, required: ['CardCode', 'DocumentLines'], additionalProperties: false } }, { name: 'sap_get_purchase_orders', description: 'Retrieve purchase orders from SAP Business One with optional filtering, selection, and pagination. Server limit: 20 records maximum per request. Use skip/top for pagination.', inputSchema: { type: 'object', properties: { filter: { type: 'string', description: 'OData $filter expression (e.g., "CardCode eq \'V20000\'" or "DocDate ge \'2024-01-01\'")' }, select: { type: 'string', description: 'OData $select expression to specify fields (e.g., "DocEntry,DocNum,CardCode,CardName,DocTotal")' }, orderby: { type: 'string', description: 'OData $orderby expression (e.g., "DocDate desc" or "DocTotal asc")' }, top: { type: 'number', description: 'Maximum number of records to return (server limit: 20, use 20 for best performance)' }, skip: { type: 'number', description: 'Number of records to skip for pagination (0-based, e.g., skip=20 for page 2, skip=40 for page 3)' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_get_purchase_order', description: 'Retrieve a single purchase order by DocEntry or DocNum from SAP Business One.', inputSchema: { type: 'object', properties: { docEntry: { type: 'number', description: 'Document entry number (DocEntry) - internal system ID' }, docNum: { type: 'number', description: 'Document number (DocNum) - user-visible document number' }, select: { type: 'string', description: 'OData $select expression to specify fields' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_create_purchase_order', description: 'Create a new purchase order in SAP Business One.', inputSchema: { type: 'object', properties: { CardCode: { type: 'string', description: 'Business partner code (vendor)' }, DocDate: { type: 'string', description: 'Document date (YYYY-MM-DD format)' }, DocDueDate: { type: 'string', description: 'Document due date (YYYY-MM-DD format)' }, TaxDate: { type: 'string', description: 'Tax date (YYYY-MM-DD format)' }, NumAtCard: { type: 'string', description: 'Vendor reference number' }, Comments: { type: 'string', description: 'Comments' }, Reference1: { type: 'string', description: 'Reference 1' }, Reference2: { type: 'string', description: 'Reference 2' }, SalesPersonCode: { type: 'number', description: 'Sales person code' }, DocCurrency: { type: 'string', description: 'Document currency' }, ShipToCode: { type: 'string', description: 'Ship to address code' }, PaymentGroupCode: { type: 'number', description: 'Payment terms group code' }, DiscountPercent: { type: 'number', description: 'Document discount percentage' }, DocumentLines: { type: 'array', items: { type: 'object', properties: { ItemCode: { type: 'string', description: 'Item code' }, ItemDescription: { type: 'string', description: 'Item description' }, Quantity: { type: 'number', description: 'Quantity' }, Price: { type: 'number', description: 'Unit price' }, DiscountPercent: { type: 'number', description: 'Discount percentage' }, WarehouseCode: { type: 'string', description: 'Warehouse code' }, VatGroup: { type: 'string', description: 'VAT group code' }, AccountCode: { type: 'string', description: 'G/L account code' }, FreeText: { type: 'string', description: 'Free text' }, ShipDate: { type: 'string', description: 'Ship date (YYYY-MM-DD format)' }, RequiredDate: { type: 'string', description: 'Required date (YYYY-MM-DD format)' } }, required: ['Quantity'] }, description: 'Purchase order lines' } }, required: ['CardCode', 'DocumentLines'], additionalProperties: false } }, { name: 'sap_get_goods_receipts', description: 'Retrieve goods receipts (GoodsReceiptPO) from SAP Business One with optional filtering, selection, and pagination. Server limit: 20 records maximum per request. Use skip/top for pagination.', inputSchema: { type: 'object', properties: { filter: { type: 'string', description: 'OData $filter expression (e.g., "CardCode eq \'V20000\'" or "DocDate ge \'2024-01-01\'")' }, select: { type: 'string', description: 'OData $select expression to specify fields (e.g., "DocEntry,DocNum,CardCode,CardName,DocTotal")' }, orderby: { type: 'string', description: 'OData $orderby expression (e.g., "DocDate desc" or "DocTotal asc")' }, top: { type: 'number', description: 'Maximum number of records to return (server limit: 20, use 20 for best performance)' }, skip: { type: 'number', description: 'Number of records to skip for pagination (0-based, e.g., skip=20 for page 2, skip=40 for page 3)' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_get_goods_receipt', description: 'Retrieve a single goods receipt (GoodsReceiptPO) by DocEntry or DocNum from SAP Business One.', inputSchema: { type: 'object', properties: { docEntry: { type: 'number', description: 'Document entry number (DocEntry) - internal system ID' }, docNum: { type: 'number', description: 'Document number (DocNum) - user-visible document number' }, select: { type: 'string', description: 'OData $select expression to specify fields' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_get_invoices', description: 'Retrieve invoices from SAP Business One with optional filtering, selection, and pagination. Server limit: 20 records maximum per request. Use skip/top for pagination.', inputSchema: { type: 'object', properties: { filter: { type: 'string', description: 'OData $filter expression (e.g., "CardCode eq \'C20000\'" or "DocDate ge \'2024-01-01\'")' }, select: { type: 'string', description: 'OData $select expression to specify fields (e.g., "DocEntry,DocNum,CardCode,CardName,DocTotal")' }, orderby: { type: 'string', description: 'OData $orderby expression (e.g., "DocDate desc" or "DocTotal asc")' }, top: { type: 'number', description: 'Maximum number of records to return (server limit: 20, use 20 for best performance)' }, skip: { type: 'number', description: 'Number of records to skip for pagination (0-based, e.g., skip=20 for page 2, skip=40 for page 3)' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_get_invoice', description: 'Retrieve a single invoice by DocEntry or DocNum from SAP Business One.', inputSchema: { type: 'object', properties: { docEntry: { type: 'number', description: 'Document entry number (DocEntry) - internal system ID' }, docNum: { type: 'number', description: 'Document number (DocNum) - user-visible document number' }, select: { type: 'string', description: 'OData $select expression to specify fields' }, expand: { type: 'string', description: 'OData $expand expression to include related data (e.g., "DocumentLines")' } }, additionalProperties: false } }, { name: 'sap_create_invoice', description: 'Create a new invoice in SAP Business One.', inputSchema: { type: 'object', properties: { CardCode: { type: 'string', description: 'Business partner code (customer)' }, DocDate: { type: 'string', description: 'Document date (YYYY-MM-DD format)' }, DocDueDate: { type: 'string', description: 'Document due date (YYYY-MM-DD format)' }, TaxDate: { type: 'string', description: 'Tax date (YYYY-MM-DD format)' }, NumAtCard: { type: 'string', description: 'Customer reference number' }, Comments: { type: 'string', description: 'Comments' }, Reference1: { type: 'string', description: 'Reference 1' }, Reference2: { type: 'string', description: 'Reference 2' }, SalesPersonCode: { type: 'number', description: 'Sales person code' }, DocCurrency: { type: 'string', description: 'Document currency' }, ShipToCode: { type: 'string', description: 'Ship to address code' }, PaymentGroupCode: { type: 'number', description: 'Payment terms group code' }, DiscountPercent: { type: 'number', description: 'Document discount percentage' }, DocumentLines: { type: 'array', items: { type: 'object', properties: { ItemCode: { type: 'string', description: 'Item code' }, ItemDescription: { type: 'string', description: 'Item description' }, Quantity: { type: 'number', description: 'Quantity' }, Price: { type: 'number', description: 'Unit price' }, DiscountPercent: { type: 'number', description: 'Discount percentage' }, WarehouseCode: { type: 'string', description: 'Warehouse code' }, VatGroup: { type: 'string', description: 'VAT group code' }, AccountCode: { type: 'string', description: 'G/L account code' }, BaseType: { type: 'number', description: 'Base document type (17 for Sales Orders)' }, BaseEntry: { type: 'number', description: 'Base document entry' }, BaseLine: { type: 'number', description: 'Base document line' }, FreeText: { type: 'string', description: 'Free text' } }, required: ['Quantity'] }, description: 'Invoice lines' } }, required: ['CardCode', 'DocumentLines'], additionalProperties: false } } ]; export class DocumentToolHandler { sapClient; constructor(sapClient) { this.sapClient = sapClient; } async handleGetOrders(args) { try { const params = documentQuerySchema.parse(args); // Build query parameters const queryParams = {}; if (params.filter) queryParams.$filter = params.filter; if (params.select) queryParams.$select = params.select; if (params.orderby) queryParams.$orderby = params.orderby; if (params.top) queryParams.$top = params.top; if (params.skip) queryParams.$skip = params.skip; if (params.expand) queryParams.$expand = params.expand; const orders = await this.sapClient.getSalesOrders(queryParams); return { success: true, count: orders.length, data: orders }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve sales orders', details: 'Check your filter syntax and ensure the session is valid' }; } } async handleGetOrder(args) { try { const params = getOrderSchema.parse(args); // Build query parameters const queryParams = {}; if (params.select) queryParams.$select = params.select; if (params.expand) queryParams.$expand = params.expand; // Create identifier object const identifier = {}; if (params.docEntry) identifier.docEntry = params.docEntry; if (params.docNum) identifier.docNum = params.docNum; const order = await this.sapClient.getSalesOrder(identifier, queryParams); return { success: true, data: order }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve sales order', details: 'Check the DocEntry/DocNum and ensure the session is valid' }; } } async handleCreateOrder(args) { try { const orderData = createSalesOrderSchema.parse(args); // Validate and format dates const formattedOrder = this.formatOrderDates(orderData); const result = await this.sapClient.createSalesOrder(formattedOrder); return { success: true, message: 'Sales order created successfully', data: { DocEntry: result.DocEntry, DocNum: result.DocNum, CardCode: result.CardCode, CardName: result.CardName, DocTotal: result.DocTotal, DocCurrency: result.DocCurrency, CreationDate: result.CreationDate } }; } catch (error) { return { success: false, error: error.message || 'Failed to create sales order', details: 'Check required fields, customer code, and line items' }; } } async handleGetPurchaseOrders(args) { try { const params = documentQuerySchema.parse(args); // Build query parameters const queryParams = {}; if (params.filter) queryParams.$filter = params.filter; if (params.select) queryParams.$select = params.select; if (params.orderby) queryParams.$orderby = params.orderby; if (params.top) queryParams.$top = params.top; if (params.skip) queryParams.$skip = params.skip; if (params.expand) queryParams.$expand = params.expand; const purchaseOrders = await this.sapClient.getPurchaseOrders(queryParams); return { success: true, count: purchaseOrders.length, data: purchaseOrders }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve purchase orders' }; } } async handleGetPurchaseOrder(args) { try { const params = getPurchaseOrderSchema.parse(args); // Build query parameters const queryParams = {}; if (params.select) queryParams.$select = params.select; if (params.expand) queryParams.$expand = params.expand; // Create identifier object const identifier = {}; if (params.docEntry) identifier.docEntry = params.docEntry; if (params.docNum) identifier.docNum = params.docNum; const purchaseOrder = await this.sapClient.getPurchaseOrder(identifier, queryParams); return { success: true, data: purchaseOrder }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve purchase order', details: 'Check the DocEntry/DocNum and ensure the session is valid' }; } } async handleCreatePurchaseOrder(args) { try { const orderData = createPurchaseOrderSchema.parse(args); // Validate and format dates const formattedOrder = this.formatOrderDates(orderData); const result = await this.sapClient.createPurchaseOrder(formattedOrder); return { success: true, message: 'Purchase order created successfully', data: { DocEntry: result.DocEntry, DocNum: result.DocNum, CardCode: result.CardCode, CardName: result.CardName, DocTotal: result.DocTotal, DocCurrency: result.DocCurrency, CreationDate: result.CreationDate } }; } catch (error) { return { success: false, error: error.message || 'Failed to create purchase order', details: 'Check required fields, vendor code, and line items' }; } } async handleGetGoodsReceipts(args) { try { const params = documentQuerySchema.parse(args); // Build query parameters const queryParams = {}; if (params.filter) queryParams.$filter = params.filter; if (params.select) queryParams.$select = params.select; if (params.orderby) queryParams.$orderby = params.orderby; if (params.top) queryParams.$top = params.top; if (params.skip) queryParams.$skip = params.skip; if (params.expand) queryParams.$expand = params.expand; const goodsReceipts = await this.sapClient.getGoodsReceipts(queryParams); return { success: true, count: goodsReceipts.length, data: goodsReceipts }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve goods receipts' }; } } async handleGetGoodsReceipt(args) { try { const params = getGoodsReceiptSchema.parse(args); // Build query parameters const queryParams = {}; if (params.select) queryParams.$select = params.select; if (params.expand) queryParams.$expand = params.expand; // Create identifier object const identifier = {}; if (params.docEntry) identifier.docEntry = params.docEntry; if (params.docNum) identifier.docNum = params.docNum; const goodsReceipt = await this.sapClient.getGoodsReceipt(identifier, queryParams); return { success: true, data: goodsReceipt }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve goods receipt', details: 'Check the DocEntry/DocNum and ensure the session is valid' }; } } async handleGetInvoices(args) { try { const params = documentQuerySchema.parse(args); // Build query parameters const queryParams = {}; if (params.filter) queryParams.$filter = params.filter; if (params.select) queryParams.$select = params.select; if (params.orderby) queryParams.$orderby = params.orderby; if (params.top) queryParams.$top = params.top; if (params.skip) queryParams.$skip = params.skip; if (params.expand) queryParams.$expand = params.expand; const invoices = await this.sapClient.getInvoices(queryParams); return { success: true, count: invoices.length, data: invoices }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve invoices', details: 'Check your filter syntax and ensure the session is valid' }; } } async handleGetInvoice(args) { try { const params = getInvoiceSchema.parse(args); // Build query parameters const queryParams = {}; if (params.select) queryParams.$select = params.select; if (params.expand) queryParams.$expand = params.expand; // Create identifier object const identifier = {}; if (params.docEntry) identifier.docEntry = params.docEntry; if (params.docNum) identifier.docNum = params.docNum; const invoice = await this.sapClient.getInvoice(identifier, queryParams); return { success: true, data: invoice }; } catch (error) { return { success: false, error: error.message || 'Failed to retrieve invoice', details: 'Check the DocEntry/DocNum and ensure the session is valid' }; } } async handleCreateInvoice(args) { try { const invoiceData = createInvoiceSchema.parse(args); // Validate and format dates const formattedInvoice = this.formatInvoiceDates(invoiceData); const result = await this.sapClient.createInvoice(formattedInvoice); return { success: true, message: 'Invoice created successfully', data: { DocEntry: result.DocEntry, DocNum: result.DocNum, CardCode: result.CardCode, CardName: result.CardName, DocTotal: result.DocTotal, DocCurrency: result.DocCurrency, CreationDate: result.CreationDate } }; } catch (error) { return { success: false, error: error.message || 'Failed to create invoice', details: 'Check required fields, customer code, and line items' }; } } formatOrderDates(order) { const formatted = { ...order }; // Format dates to SAP B1 format if provided if (formatted.DocDate) { formatted.DocDate = this.formatDateForSAP(formatted.DocDate); } if (formatted.DocDueDate) { formatted.DocDueDate = this.formatDateForSAP(formatted.DocDueDate); } if (formatted.TaxDate) { formatted.TaxDate = this.formatDateForSAP(formatted.TaxDate); } // Format line dates if (formatted.DocumentLines) { formatted.DocumentLines = formatted.DocumentLines.map((line) => { const formattedLine = { ...line }; if (formattedLine.ShipDate) { formattedLine.ShipDate = this.formatDateForSAP(formattedLine.ShipDate); } if (formattedLine.RequiredDate) { formattedLine.RequiredDate = this.formatDateForSAP(formattedLine.RequiredDate); } return formattedLine; }); } return formatted; } formatInvoiceDates(invoice) { const formatted = { ...invoice }; // Format dates to SAP B1 format if provided if (formatted.DocDate) { formatted.DocDate = this.formatDateForSAP(formatted.DocDate); } if (formatted.DocDueDate) { formatted.DocDueDate = this.formatDateForSAP(formatted.DocDueDate); } if (formatted.TaxDate) { formatted.TaxDate = this.formatDateForSAP(formatted.TaxDate); } return formatted; } formatDateForSAP(dateString) { // Ensure date is in YYYY-MM-DD format for SAP B1 const date = new Date(dateString); if (isNaN(date.getTime())) { throw new Error(`Invalid date format: ${dateString}. Use YYYY-MM-DD format.`); } return date.toISOString().split('T')[0]; } validateDocumentLines(lines) { if (!lines || lines.length === 0) { throw new Error('At least one document line is required'); } for (const line of lines) { if (!line.Quantity || line.Quantity <= 0) { throw new Error('Each line must have a positive quantity'); } if (!line.ItemCode && !line.ItemDescription && !line.AccountCode) { throw new Error('Each line must have either ItemCode, ItemDescription, or AccountCode'); } } } } //# sourceMappingURL=documents.js.map