sap-b1-mcp-server
Version:
SAP Business One Service Layer MCP Server
1,030 lines • 44.6 kB
JavaScript
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