chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,218 @@
import type { CreateBusinessPartnerParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const createBusinessPartnerTool: ToolConfig<CreateBusinessPartnerParams, SapProxyResponse> =
{
id: 'sap_s4hana_create_business_partner',
name: 'SAP S/4HANA Create Business Partner',
description:
'Create a business partner in SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_BusinessPartner). For Person category 1 provide FirstName and LastName. For Organization category 2 provide OrganizationBPName1.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
businessPartnerCategory: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'BusinessPartnerCategory: "1" Person, "2" Organization, "3" Group',
},
businessPartnerGrouping: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'BusinessPartnerGrouping (number range / role grouping configured in S/4HANA, e.g. "0001")',
},
firstName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'FirstName (required for Person)',
},
lastName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'LastName (required for Person)',
},
organizationBPName1: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OrganizationBPName1 (required for Organization)',
},
body: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'Optional additional A_BusinessPartner fields merged into the create payload',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const extra = parseJsonInput<Record<string, unknown>>(params.body, 'body') ?? {}
const extraHasName = (key: string) => Object.hasOwn(extra, key) && Boolean(extra[key])
if (params.businessPartnerCategory === '1') {
const hasFirst = Boolean(params.firstName) || extraHasName('FirstName')
const hasLast = Boolean(params.lastName) || extraHasName('LastName')
if (!hasFirst || !hasLast) {
throw new Error('BusinessPartnerCategory "1" (Person) requires FirstName and LastName')
}
} else if (params.businessPartnerCategory === '2') {
const hasOrgName =
Boolean(params.organizationBPName1) || extraHasName('OrganizationBPName1')
if (!hasOrgName) {
throw new Error(
'BusinessPartnerCategory "2" (Organization) requires OrganizationBPName1'
)
}
}
const payload: Record<string, unknown> = {
...extra,
BusinessPartnerCategory: params.businessPartnerCategory,
BusinessPartnerGrouping: params.businessPartnerGrouping,
}
if (params.firstName) payload.FirstName = params.firstName
if (params.lastName) payload.LastName = params.lastName
if (params.organizationBPName1) payload.OrganizationBPName1 = params.organizationBPName1
return {
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: '/A_BusinessPartner',
method: 'POST',
query: { $format: 'json' },
body: payload,
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (201 on success)' },
data: {
type: 'json',
description: 'Created A_BusinessPartner entity (under d in OData v2)',
properties: {
BusinessPartner: {
type: 'string',
description: 'Generated business partner key (up to 10 chars)',
},
BusinessPartnerFullName: {
type: 'string',
description: 'Full name (concatenated first/last or organization name)',
optional: true,
},
BusinessPartnerCategory: {
type: 'string',
description: '"1" Person, "2" Organization, "3" Group',
optional: true,
},
BusinessPartnerGrouping: {
type: 'string',
description: 'Grouping / number range used to assign the key',
optional: true,
},
BusinessPartnerType: {
type: 'string',
description: 'Business partner type (tenant-configured)',
optional: true,
},
BusinessPartnerUUID: {
type: 'string',
description: 'GUID identifier for the business partner',
optional: true,
},
FirstName: { type: 'string', description: 'First name (Person)', optional: true },
LastName: { type: 'string', description: 'Last name (Person)', optional: true },
OrganizationBPName1: {
type: 'string',
description: 'Organization name line 1',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Date the partner was created (OData /Date(...)/ literal)',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the business partner',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Date of last change (OData /Date(...)/ literal)',
optional: true,
},
},
},
},
}
@@ -0,0 +1,188 @@
import type { CreatePurchaseOrderParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const createPurchaseOrderTool: ToolConfig<CreatePurchaseOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_create_purchase_order',
name: 'SAP S/4HANA Create Purchase Order',
description:
'Create a purchase order in SAP S/4HANA Cloud (API_PURCHASEORDER_PROCESS_SRV, A_PurchaseOrder). PurchaseOrder is auto-assigned by SAP from the document number range; provide line items via the body parameter.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
purchaseOrderType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchaseOrderType (e.g., "NB" Standard PO)',
},
companyCode: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'CompanyCode (4 chars, e.g., "1010")',
},
purchasingOrganization: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchasingOrganization (4 chars)',
},
purchasingGroup: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchasingGroup (3 chars)',
},
supplier: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Supplier business partner key (up to 10 chars)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'A_PurchaseOrder body containing to_PurchaseOrderItem deep-insert items (required by SAP) plus any additional header fields, e.g., {"to_PurchaseOrderItem":[{"PurchaseOrderItem":"10","Material":"TG11","OrderQuantity":"5","Plant":"1010","PurchaseOrderQuantityUnit":"PC","NetPriceAmount":"100.00","DocumentCurrency":"USD"}]}.',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const extra = parseJsonInput<Record<string, unknown>>(params.body, 'body') ?? {}
const items = Array.isArray(extra.to_PurchaseOrderItem) ? extra.to_PurchaseOrderItem : null
if (!items || items.length === 0) {
throw new Error(
'body must include a non-empty "to_PurchaseOrderItem" array of purchase order line items'
)
}
const payload: Record<string, unknown> = {
...extra,
PurchaseOrderType: params.purchaseOrderType,
CompanyCode: params.companyCode,
PurchasingOrganization: params.purchasingOrganization,
PurchasingGroup: params.purchasingGroup,
Supplier: params.supplier,
}
return {
...baseProxyBody(params),
service: 'API_PURCHASEORDER_PROCESS_SRV',
path: '/A_PurchaseOrder',
method: 'POST',
query: { $format: 'json' },
body: payload,
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; created entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'Created A_PurchaseOrder entity',
properties: {
PurchaseOrder: { type: 'string', description: 'Auto-assigned purchase order number' },
PurchaseOrderType: { type: 'string', description: 'PO document type' },
CompanyCode: { type: 'string', description: 'Company code' },
PurchasingOrganization: { type: 'string', description: 'Purchasing organization' },
PurchasingGroup: { type: 'string', description: 'Purchasing group' },
Supplier: { type: 'string', description: 'Supplier business partner key' },
DocumentCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
NetAmount: {
type: 'string',
description: 'Net amount of the purchase order',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
to_PurchaseOrderItem: {
type: 'json',
description: 'Created PO items returned in deep insert',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,166 @@
import type { CreatePurchaseRequisitionParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const createPurchaseRequisitionTool: ToolConfig<
CreatePurchaseRequisitionParams,
SapProxyResponse
> = {
id: 'sap_s4hana_create_purchase_requisition',
name: 'SAP S/4HANA Create Purchase Requisition',
description:
'Create a purchase requisition in SAP S/4HANA Cloud (API_PURCHASEREQ_PROCESS_SRV, A_PurchaseRequisitionHeader). PurchaseRequisition is auto-assigned by SAP from the document number range; provide line items via the to_PurchaseReqnItem deep-insert array. Note: API_PURCHASEREQ_PROCESS_SRV is deprecated since S/4HANA Cloud Public Edition 2402; the successor is API_PURCHASEREQUISITION_2 (OData v4). This tool still works against tenants where the legacy service is enabled.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
purchaseRequisitionType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchaseRequisitionType (e.g., "NB" Standard PR)',
},
items: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'to_PurchaseReqnItem deep-insert array (e.g., [{"PurchaseRequisitionItem":"10","Material":"TG11","RequestedQuantity":"5","Plant":"1010","BaseUnit":"PC","DeliveryDate":"/Date(1735689600000)/"}])',
},
body: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description:
'Additional A_PurchaseRequisitionHeader fields merged into the create payload (e.g., {"PurReqnDescription":"Office supplies"})',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const items = parseJsonInput<Array<Record<string, unknown>>>(params.items, 'items')
if (!Array.isArray(items) || items.length === 0) {
throw new Error('items must be a non-empty JSON array of purchase requisition items')
}
const extra = parseJsonInput<Record<string, unknown>>(params.body, 'body') ?? {}
const payload: Record<string, unknown> = {
...extra,
PurchaseRequisitionType: params.purchaseRequisitionType,
to_PurchaseReqnItem: items,
}
return {
...baseProxyBody(params),
service: 'API_PURCHASEREQ_PROCESS_SRV',
path: '/A_PurchaseRequisitionHeader',
method: 'POST',
query: { $format: 'json' },
body: payload,
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; created entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'Created A_PurchaseRequisitionHeader entity',
properties: {
PurchaseRequisition: {
type: 'string',
description: 'Auto-assigned purchase requisition number',
},
PurchaseRequisitionType: {
type: 'string',
description: 'PR document type (e.g., NB)',
},
PurReqnDescription: {
type: 'string',
description: 'Purchase requisition description',
optional: true,
},
SourceDetermination: {
type: 'string',
description: 'Source-of-supply determination flag',
optional: true,
},
to_PurchaseReqnItem: {
type: 'json',
description: 'Created PR items returned in deep insert',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,191 @@
import type { CreateSalesOrderParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const createSalesOrderTool: ToolConfig<CreateSalesOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_create_sales_order',
name: 'SAP S/4HANA Create Sales Order',
description:
'Create a sales order in SAP S/4HANA Cloud (API_SALES_ORDER_SRV, A_SalesOrder) with deep insert of sales order items via to_Item.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
salesOrderType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SalesOrderType (e.g., "OR" Standard Order)',
},
salesOrganization: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SalesOrganization (4 chars, e.g., "1010")',
},
distributionChannel: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'DistributionChannel (2 chars, e.g., "10")',
},
organizationDivision: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'OrganizationDivision (2 chars, e.g., "00")',
},
soldToParty: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SoldToParty business partner key (up to 10 chars)',
},
items: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'Array of sales order items for to_Item deep insert. Each item should include Material and RequestedQuantity (e.g., [{"Material":"TG11","RequestedQuantity":"1"}]).',
},
body: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'Optional additional A_SalesOrder fields merged into the create payload',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const items = parseJsonInput<Array<Record<string, unknown>>>(params.items, 'items')
if (!Array.isArray(items) || items.length === 0) {
throw new Error('items must be a non-empty JSON array of sales order item objects')
}
const extra = parseJsonInput<Record<string, unknown>>(params.body, 'body') ?? {}
const payload: Record<string, unknown> = {
...extra,
SalesOrderType: params.salesOrderType,
SalesOrganization: params.salesOrganization,
DistributionChannel: params.distributionChannel,
OrganizationDivision: params.organizationDivision,
SoldToParty: params.soldToParty,
to_Item: items,
}
return {
...baseProxyBody(params),
service: 'API_SALES_ORDER_SRV',
path: '/A_SalesOrder',
method: 'POST',
query: { $format: 'json' },
body: payload,
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (201 on create)' },
data: {
type: 'json',
description: 'OData v2 response envelope; created entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'Created A_SalesOrder entity',
properties: {
SalesOrder: { type: 'string', description: 'Newly assigned sales order number' },
SalesOrderType: { type: 'string', description: 'Sales document type' },
SalesOrganization: { type: 'string', description: 'Sales organization' },
DistributionChannel: { type: 'string', description: 'Distribution channel' },
OrganizationDivision: { type: 'string', description: 'Division' },
SoldToParty: { type: 'string', description: 'Sold-to business partner' },
TotalNetAmount: { type: 'string', description: 'Total net amount' },
TransactionCurrency: { type: 'string', description: 'Document currency' },
CreationDate: { type: 'string', description: 'Creation date' },
OverallSDProcessStatus: {
type: 'string',
description: 'Overall sales document process status',
optional: true,
},
OverallTotalDeliveryStatus: {
type: 'string',
description: 'Overall total delivery status',
optional: true,
},
to_Item: {
type: 'json',
description: 'Deep-inserted sales order items as returned by SAP',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,112 @@
import type { DeleteSalesOrderParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteSalesOrderTool: ToolConfig<DeleteSalesOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_delete_sales_order',
name: 'SAP S/4HANA Delete Sales Order',
description:
'Delete an A_SalesOrder entity in SAP S/4HANA Cloud (API_SALES_ORDER_SRV). Only orders without subsequent documents (deliveries, invoices) can be deleted; otherwise reject items via update instead.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
salesOrder: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SalesOrder key to delete (string, up to 10 characters)',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_SALES_ORDER_SRV',
path: `/A_SalesOrder(${quoteOdataKey(params.salesOrder)})`,
method: 'DELETE',
ifMatch: params.ifMatch || '*',
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description: 'Null on successful deletion (SAP returns 204 No Content)',
optional: true,
},
},
}
@@ -0,0 +1,263 @@
import type { GetBillingDocumentParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getBillingDocumentTool: ToolConfig<GetBillingDocumentParams, SapProxyResponse> = {
id: 'sap_s4hana_get_billing_document',
name: 'SAP S/4HANA Get Billing Document',
description:
'Retrieve a single billing document (customer invoice) by BillingDocument key from SAP S/4HANA Cloud (API_BILLING_DOCUMENT_SRV, A_BillingDocument).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
billingDocument: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'BillingDocument key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_Item,to_Partner,to_PricingElement")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BILLING_DOCUMENT_SRV',
path: `/A_BillingDocument(${quoteOdataKey(params.billingDocument)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_BillingDocument entity',
properties: {
BillingDocument: { type: 'string', description: 'Billing document number' },
SDDocumentCategory: {
type: 'string',
description: 'SD document category',
optional: true,
},
BillingDocumentCategory: {
type: 'string',
description: 'Billing document category',
optional: true,
},
BillingDocumentType: {
type: 'string',
description: 'Billing document type',
optional: true,
},
BillingDocumentDate: {
type: 'string',
description: 'Billing document date (OData /Date(ms)/)',
optional: true,
},
BillingDocumentIsCancelled: {
type: 'boolean',
description: 'Whether the billing document is cancelled',
optional: true,
},
CancelledBillingDocument: {
type: 'string',
description: 'Cancelled billing document number',
optional: true,
},
TotalNetAmount: {
type: 'string',
description: 'Total net amount (Edm.Decimal as string)',
optional: true,
},
TaxAmount: {
type: 'string',
description: 'Tax amount (Edm.Decimal as string)',
optional: true,
},
TotalGrossAmount: {
type: 'string',
description: 'Total gross amount (Edm.Decimal as string)',
optional: true,
},
TransactionCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
SoldToParty: {
type: 'string',
description: 'Sold-to business partner',
optional: true,
},
PayerParty: { type: 'string', description: 'Payer party', optional: true },
SalesOrganization: {
type: 'string',
description: 'Sales organization',
optional: true,
},
DistributionChannel: {
type: 'string',
description: 'Distribution channel',
optional: true,
},
Division: { type: 'string', description: 'Division', optional: true },
CompanyCode: { type: 'string', description: 'Company code', optional: true },
FiscalYear: { type: 'string', description: 'Fiscal year', optional: true },
OverallBillingStatus: {
type: 'string',
description: 'Overall billing status',
optional: true,
},
AccountingPostingStatus: {
type: 'string',
description: 'Accounting posting status',
optional: true,
},
AccountingTransferStatus: {
type: 'string',
description: 'Accounting transfer status',
optional: true,
},
InvoiceClearingStatus: {
type: 'string',
description: 'Invoice clearing status',
optional: true,
},
AccountingDocument: {
type: 'string',
description: 'Linked accounting document',
optional: true,
},
CustomerPaymentTerms: {
type: 'string',
description: 'Customer payment terms',
optional: true,
},
PaymentMethod: { type: 'string', description: 'Payment method', optional: true },
DocumentReferenceID: {
type: 'string',
description: 'Document reference ID',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (OData /Date(ms)/)',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change date-time (Edm.DateTimeOffset)',
optional: true,
},
to_Item: {
type: 'json',
description: 'Billing document items (when $expand=to_Item)',
optional: true,
},
to_Partner: {
type: 'json',
description: 'Billing document partners (when $expand=to_Partner)',
optional: true,
},
to_PricingElement: {
type: 'json',
description: 'Billing document pricing elements (when $expand=to_PricingElement)',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,185 @@
import type { GetBusinessPartnerParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getBusinessPartnerTool: ToolConfig<GetBusinessPartnerParams, SapProxyResponse> = {
id: 'sap_s4hana_get_business_partner',
name: 'SAP S/4HANA Get Business Partner',
description:
'Retrieve a single business partner by BusinessPartner key from SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_BusinessPartner).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
businessPartner: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'BusinessPartner key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand ($expand)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: `/A_BusinessPartner(${quoteOdataKey(params.businessPartner)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'A_BusinessPartner entity (under d in OData v2)',
properties: {
BusinessPartner: { type: 'string', description: 'Business partner key (up to 10 chars)' },
BusinessPartnerFullName: {
type: 'string',
description: 'Full name (concatenated first/last or organization name)',
optional: true,
},
BusinessPartnerCategory: {
type: 'string',
description: '"1" Person, "2" Organization, "3" Group',
optional: true,
},
BusinessPartnerGrouping: {
type: 'string',
description: 'Grouping / number range (tenant-configured)',
optional: true,
},
BusinessPartnerType: {
type: 'string',
description: 'Business partner type (tenant-configured)',
optional: true,
},
BusinessPartnerUUID: {
type: 'string',
description: 'GUID identifier for the business partner',
optional: true,
},
BusinessPartnerIsBlocked: {
type: 'boolean',
description: 'Whether the business partner is centrally blocked',
optional: true,
},
FirstName: { type: 'string', description: 'First name (Person)', optional: true },
LastName: { type: 'string', description: 'Last name (Person)', optional: true },
OrganizationBPName1: {
type: 'string',
description: 'Organization name line 1',
optional: true,
},
CorrespondenceLanguage: {
type: 'string',
description: 'Correspondence language (2-char code, e.g. "EN")',
optional: true,
},
SearchTerm1: { type: 'string', description: 'Search term 1', optional: true },
SearchTerm2: { type: 'string', description: 'Search term 2', optional: true },
CreationDate: {
type: 'string',
description: 'Date the partner was created (OData /Date(...)/ literal)',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the business partner',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Date of last change (OData /Date(...)/ literal)',
optional: true,
},
LastChangedByUser: {
type: 'string',
description: 'User who last changed the business partner',
optional: true,
},
},
},
},
}
+153
View File
@@ -0,0 +1,153 @@
import type { GetCustomerParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getCustomerTool: ToolConfig<GetCustomerParams, SapProxyResponse> = {
id: 'sap_s4hana_get_customer',
name: 'SAP S/4HANA Get Customer',
description:
'Retrieve a single customer by Customer key from SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_Customer).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
customer: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Customer key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_CustomerCompany,to_CustomerSalesArea")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: `/A_Customer(${quoteOdataKey(params.customer)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'object',
description: 'A_Customer entity',
properties: {
Customer: { type: 'string', description: 'Customer key (up to 10 characters)' },
CustomerName: { type: 'string', description: 'Name of customer' },
CustomerFullName: { type: 'string', description: 'Full name of the customer' },
CustomerAccountGroup: { type: 'string', description: 'Customer account group' },
CustomerClassification: { type: 'string', description: 'Customer classification code' },
CustomerCorporateGroup: { type: 'string', description: 'Corporate group code' },
AuthorizationGroup: { type: 'string', description: 'Authorization group' },
Supplier: { type: 'string', description: 'Linked supplier account number' },
FiscalAddress: { type: 'string', description: 'Fiscal address ID' },
Industry: { type: 'string', description: 'Industry key' },
NielsenRegion: { type: 'string', description: 'Nielsen ID' },
ResponsibleType: { type: 'string', description: 'Responsible type' },
NFPartnerIsNaturalPerson: { type: 'string', description: 'Natural person indicator' },
InternationalLocationNumber1: {
type: 'string',
description: 'International location number 1',
},
TaxNumberType: { type: 'string', description: 'Tax number type' },
VATRegistration: { type: 'string', description: 'VAT registration number' },
DeletionIndicator: { type: 'boolean', description: 'Central deletion flag' },
OrderIsBlockedForCustomer: {
type: 'string',
description: 'Central order block reason code',
},
PostingIsBlocked: { type: 'boolean', description: 'Central posting block flag' },
DeliveryIsBlocked: { type: 'string', description: 'Central delivery block reason code' },
BillingIsBlockedForCustomer: {
type: 'string',
description: 'Central billing block reason code',
},
CreationDate: { type: 'string', description: 'Creation date (OData v2 epoch)' },
CreatedByUser: { type: 'string', description: 'User who created the customer' },
},
},
},
}
@@ -0,0 +1,195 @@
import type { GetInboundDeliveryParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getInboundDeliveryTool: ToolConfig<GetInboundDeliveryParams, SapProxyResponse> = {
id: 'sap_s4hana_get_inbound_delivery',
name: 'SAP S/4HANA Get Inbound Delivery',
description:
'Retrieve a single inbound delivery by DeliveryDocument key from SAP S/4HANA Cloud (API_INBOUND_DELIVERY_SRV;v=0002, A_InbDeliveryHeader).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
deliveryDocument: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'DeliveryDocument key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_DeliveryDocumentItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_INBOUND_DELIVERY_SRV;v=0002',
path: `/A_InbDeliveryHeader(${quoteOdataKey(params.deliveryDocument)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_InbDeliveryHeader entity',
properties: {
DeliveryDocument: { type: 'string', description: 'Inbound delivery number' },
DeliveryDocumentType: { type: 'string', description: 'Delivery document type' },
SDDocumentCategory: {
type: 'string',
description: 'SD document category (e.g., 7 = inbound delivery)',
optional: true,
},
ReceivingPlant: { type: 'string', description: 'Receiving plant', optional: true },
Supplier: {
type: 'string',
description: 'Supplier business partner',
optional: true,
},
ShipToParty: {
type: 'string',
description: 'Ship-to business partner',
optional: true,
},
DeliveryDate: {
type: 'string',
description: 'Delivery date (Edm.DateTime)',
optional: true,
},
ActualGoodsMovementDate: {
type: 'string',
description: 'Actual goods movement (receipt) date (Edm.DateTime)',
optional: true,
},
PlannedGoodsMovementDate: {
type: 'string',
description: 'Planned goods movement date (Edm.DateTime)',
optional: true,
},
OverallSDProcessStatus: {
type: 'string',
description: 'Overall SD process (delivery) status',
optional: true,
},
OverallGoodsMovementStatus: {
type: 'string',
description: 'Overall goods movement status',
optional: true,
},
DocumentDate: {
type: 'string',
description: 'Document date (Edm.DateTime)',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (Edm.DateTime)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (Edm.DateTime)',
optional: true,
},
to_DeliveryDocumentItem: {
type: 'json',
description: 'Delivery items (when $expand=to_DeliveryDocumentItem)',
optional: true,
},
to_DeliveryDocumentPartner: {
type: 'json',
description: 'Delivery partners (when $expand=to_DeliveryDocumentPartner)',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,178 @@
import type { GetMaterialDocumentParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getMaterialDocumentTool: ToolConfig<GetMaterialDocumentParams, SapProxyResponse> = {
id: 'sap_s4hana_get_material_document',
name: 'SAP S/4HANA Get Material Document',
description:
'Retrieve a single material document header by composite key (MaterialDocument + MaterialDocumentYear) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
materialDocumentYear: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'MaterialDocumentYear (4-character year, e.g., "2024")',
},
materialDocument: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'MaterialDocument key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_MaterialDocumentItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_MATERIAL_DOCUMENT_SRV',
path: `/A_MaterialDocumentHeader(MaterialDocument=${quoteOdataKey(params.materialDocument)},MaterialDocumentYear=${quoteOdataKey(params.materialDocumentYear)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description:
'OData payload containing the A_MaterialDocumentHeader entity (and optionally to_MaterialDocumentItem when expanded)',
properties: {
MaterialDocumentYear: {
type: 'string',
description: 'Material document year (4-digit fiscal year)',
},
MaterialDocument: { type: 'string', description: 'Material document number' },
DocumentDate: { type: 'string', description: 'Document date (OData /Date(...)/ string)' },
PostingDate: { type: 'string', description: 'Posting date (OData /Date(...)/ string)' },
MaterialDocumentHeaderText: {
type: 'string',
description: 'Header text describing the material document',
optional: true,
},
ReferenceDocument: {
type: 'string',
description: 'Reference document number',
optional: true,
},
GoodsMovementCode: {
type: 'string',
description: 'Goods movement code (e.g., 01 GR for PO, 03 GI to cost center)',
},
InventoryTransactionType: {
type: 'string',
description: 'Inventory transaction type indicator',
optional: true,
},
CreatedByUser: { type: 'string', description: 'User who created the material document' },
CreationDate: { type: 'string', description: 'Creation date (OData /Date(...)/ string)' },
CreationTime: { type: 'string', description: 'Creation time (OData PT...S string)' },
VersionForPrintingSlip: {
type: 'string',
description: 'Version for printing the goods movement slip',
optional: true,
},
ManualPrintIsTriggered: {
type: 'boolean',
description: 'Indicates whether manual print was triggered for this document',
optional: true,
},
CtrlPostgForExtWhseMgmtSyst: {
type: 'string',
description: 'Control posting for external warehouse management system',
optional: true,
},
to_MaterialDocumentItem: {
type: 'json',
description:
'Material document items (only present when $expand=to_MaterialDocumentItem is supplied)',
optional: true,
},
},
},
},
}
@@ -0,0 +1,209 @@
import type { GetOutboundDeliveryParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getOutboundDeliveryTool: ToolConfig<GetOutboundDeliveryParams, SapProxyResponse> = {
id: 'sap_s4hana_get_outbound_delivery',
name: 'SAP S/4HANA Get Outbound Delivery',
description:
'Retrieve a single outbound delivery by DeliveryDocument key from SAP S/4HANA Cloud (API_OUTBOUND_DELIVERY_SRV;v=0002, A_OutbDeliveryHeader).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
deliveryDocument: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'DeliveryDocument key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_DeliveryDocumentItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_OUTBOUND_DELIVERY_SRV;v=0002',
path: `/A_OutbDeliveryHeader(${quoteOdataKey(params.deliveryDocument)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_OutbDeliveryHeader entity',
properties: {
DeliveryDocument: { type: 'string', description: 'Outbound delivery number' },
DeliveryDocumentType: { type: 'string', description: 'Delivery document type' },
SDDocumentCategory: {
type: 'string',
description: 'SD document category (e.g., J = outbound delivery)',
optional: true,
},
ShippingPoint: {
type: 'string',
description: 'Shipping point',
optional: true,
},
ShippingType: {
type: 'string',
description: 'Shipping type',
optional: true,
},
ShipToParty: {
type: 'string',
description: 'Ship-to business partner',
optional: true,
},
SoldToParty: {
type: 'string',
description: 'Sold-to business partner',
optional: true,
},
DeliveryDate: {
type: 'string',
description: 'Delivery date (Edm.DateTime)',
optional: true,
},
ActualGoodsMovementDate: {
type: 'string',
description: 'Actual goods issue date (Edm.DateTime)',
optional: true,
},
PlannedGoodsIssueDate: {
type: 'string',
description: 'Planned goods issue date (Edm.DateTime)',
optional: true,
},
OverallSDProcessStatus: {
type: 'string',
description: 'Overall SD process (delivery) status',
optional: true,
},
OverallGoodsMovementStatus: {
type: 'string',
description: 'Overall goods movement status',
optional: true,
},
TransactionCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
DocumentDate: {
type: 'string',
description: 'Document date (Edm.DateTime)',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (Edm.DateTime)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (Edm.DateTime)',
optional: true,
},
to_DeliveryDocumentItem: {
type: 'json',
description: 'Delivery items (when $expand=to_DeliveryDocumentItem)',
optional: true,
},
to_DeliveryDocumentPartner: {
type: 'json',
description: 'Delivery partners (when $expand=to_DeliveryDocumentPartner)',
optional: true,
},
},
},
},
},
},
}
+212
View File
@@ -0,0 +1,212 @@
import type { GetProductParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getProductTool: ToolConfig<GetProductParams, SapProxyResponse> = {
id: 'sap_s4hana_get_product',
name: 'SAP S/4HANA Get Product',
description:
'Retrieve a single product (material) by Product key from SAP S/4HANA Cloud (API_PRODUCT_SRV, A_Product).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
product: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Product key (string, up to 40 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_Description")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_PRODUCT_SRV',
path: `/A_Product(${quoteOdataKey(params.product)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_Product entity',
properties: {
Product: {
type: 'string',
description: 'Product (material) number',
optional: true,
},
ProductType: {
type: 'string',
description: 'Product type (e.g., FERT, HAWA)',
optional: true,
},
ProductGroup: { type: 'string', description: 'Material group', optional: true },
BaseUnit: { type: 'string', description: 'Base unit of measure', optional: true },
Brand: { type: 'string', description: 'Brand', optional: true },
Division: { type: 'string', description: 'Division', optional: true },
GrossWeight: { type: 'string', description: 'Gross weight', optional: true },
NetWeight: { type: 'string', description: 'Net weight', optional: true },
WeightUnit: {
type: 'string',
description: 'Weight unit of measure',
optional: true,
},
CrossPlantStatus: {
type: 'string',
description: 'Cross-plant material status',
optional: true,
},
IsMarkedForDeletion: {
type: 'boolean',
description: 'Deletion flag',
optional: true,
},
ProductStandardID: {
type: 'string',
description: 'Standard product ID (e.g., GTIN)',
optional: true,
},
ItemCategoryGroup: {
type: 'string',
description: 'Item category group',
optional: true,
},
ProductOldID: {
type: 'string',
description: 'Legacy/old product ID',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the product',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
LastChangedByUser: {
type: 'string',
description: 'User who last changed the product',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change timestamp (Edm.DateTimeOffset)',
optional: true,
},
to_Description: {
type: 'json',
description: 'Product descriptions (when $expand=to_Description)',
optional: true,
},
to_Plant: {
type: 'json',
description: 'Plant-level data (when $expand=to_Plant)',
optional: true,
},
to_ProductSales: {
type: 'json',
description: 'Sales data (when $expand=to_ProductSales)',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,187 @@
import type { GetPurchaseOrderParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getPurchaseOrderTool: ToolConfig<GetPurchaseOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_get_purchase_order',
name: 'SAP S/4HANA Get Purchase Order',
description:
'Retrieve a single purchase order by PurchaseOrder key from SAP S/4HANA Cloud (API_PURCHASEORDER_PROCESS_SRV, A_PurchaseOrder).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
purchaseOrder: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchaseOrder key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_PurchaseOrderItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_PURCHASEORDER_PROCESS_SRV',
path: `/A_PurchaseOrder(${quoteOdataKey(params.purchaseOrder.trim())})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_PurchaseOrder entity',
properties: {
PurchaseOrder: { type: 'string', description: 'Purchase order number' },
PurchaseOrderType: { type: 'string', description: 'PO document type' },
CompanyCode: { type: 'string', description: 'Company code' },
PurchasingOrganization: { type: 'string', description: 'Purchasing organization' },
PurchasingGroup: { type: 'string', description: 'Purchasing group' },
Supplier: { type: 'string', description: 'Supplier business partner key' },
DocumentCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
NetAmount: {
type: 'string',
description: 'Net amount of the purchase order',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the PO',
optional: true,
},
PurchaseOrderDate: {
type: 'string',
description: 'Purchase order date',
optional: true,
},
ValidityStartDate: {
type: 'string',
description: 'Validity start date',
optional: true,
},
ValidityEndDate: {
type: 'string',
description: 'Validity end date',
optional: true,
},
IncotermsClassification: {
type: 'string',
description: 'Incoterms classification (e.g., FOB)',
optional: true,
},
PaymentTerms: {
type: 'string',
description: 'Payment terms key',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change timestamp (OData /Date(ms)/)',
optional: true,
},
to_PurchaseOrderItem: {
type: 'json',
description: 'Expanded PO items (when $expand=to_PurchaseOrderItem)',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,152 @@
import type { GetPurchaseRequisitionParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getPurchaseRequisitionTool: ToolConfig<
GetPurchaseRequisitionParams,
SapProxyResponse
> = {
id: 'sap_s4hana_get_purchase_requisition',
name: 'SAP S/4HANA Get Purchase Requisition',
description:
'Retrieve a single purchase requisition by PurchaseRequisition key from SAP S/4HANA Cloud (API_PURCHASEREQ_PROCESS_SRV, A_PurchaseRequisitionHeader). Note: API_PURCHASEREQ_PROCESS_SRV is deprecated since S/4HANA Cloud Public Edition 2402; the successor is API_PURCHASEREQUISITION_2 (OData v4). This tool still works against tenants where the legacy service is enabled.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
purchaseRequisition: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchaseRequisition key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_PurchaseReqnItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_PURCHASEREQ_PROCESS_SRV',
path: `/A_PurchaseRequisitionHeader(${quoteOdataKey(params.purchaseRequisition)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_PurchaseRequisitionHeader entity',
properties: {
PurchaseRequisition: {
type: 'string',
description: 'Purchase requisition number',
},
PurchaseRequisitionType: {
type: 'string',
description: 'PR document type (e.g., NB)',
},
PurReqnDescription: {
type: 'string',
description: 'Purchase requisition description',
optional: true,
},
SourceDetermination: {
type: 'string',
description: 'Source-of-supply determination flag',
optional: true,
},
to_PurchaseReqnItem: {
type: 'json',
description: 'Expanded PR items (when $expand=to_PurchaseReqnItem)',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,185 @@
import type { GetSalesOrderParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getSalesOrderTool: ToolConfig<GetSalesOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_get_sales_order',
name: 'SAP S/4HANA Get Sales Order',
description:
'Retrieve a single sales order by SalesOrder key from SAP S/4HANA Cloud (API_SALES_ORDER_SRV, A_SalesOrder).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
salesOrder: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SalesOrder key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_Item")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_SALES_ORDER_SRV',
path: `/A_SalesOrder(${quoteOdataKey(params.salesOrder)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_SalesOrder entity',
properties: {
SalesOrder: { type: 'string', description: 'Sales order number' },
SalesOrderType: { type: 'string', description: 'Sales document type' },
SalesOrganization: { type: 'string', description: 'Sales organization' },
DistributionChannel: { type: 'string', description: 'Distribution channel' },
OrganizationDivision: { type: 'string', description: 'Division' },
SoldToParty: { type: 'string', description: 'Sold-to business partner' },
PurchaseOrderByCustomer: {
type: 'string',
description: 'Customer purchase order reference',
optional: true,
},
SalesOrderDate: {
type: 'string',
description: 'Sales order date (OData /Date(ms)/)',
optional: true,
},
RequestedDeliveryDate: {
type: 'string',
description: 'Requested delivery date (OData /Date(ms)/)',
optional: true,
},
PricingDate: {
type: 'string',
description: 'Pricing date (OData /Date(ms)/)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (OData /Date(ms)/)',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change timestamp (OData /Date(ms)/)',
optional: true,
},
TotalNetAmount: { type: 'string', description: 'Total net amount' },
TransactionCurrency: { type: 'string', description: 'Document currency' },
CreationDate: { type: 'string', description: 'Creation date' },
OverallSDProcessStatus: {
type: 'string',
description: 'Overall sales document process status',
optional: true,
},
OverallTotalDeliveryStatus: {
type: 'string',
description: 'Overall total delivery status',
optional: true,
},
OverallSDDocumentRejectionSts: {
type: 'string',
description: 'Overall sales document rejection status',
optional: true,
},
to_Item: {
type: 'json',
description: 'Sales order items (when $expand=to_Item)',
optional: true,
},
},
},
},
},
},
}
+276
View File
@@ -0,0 +1,276 @@
import type { GetSupplierParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getSupplierTool: ToolConfig<GetSupplierParams, SapProxyResponse> = {
id: 'sap_s4hana_get_supplier',
name: 'SAP S/4HANA Get Supplier',
description:
'Retrieve a single supplier by Supplier key from SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_Supplier).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
supplier: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Supplier key (string, up to 10 characters)',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_SupplierCompany,to_SupplierPurchasingOrg")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: `/A_Supplier(${quoteOdataKey(params.supplier)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_Supplier entity',
properties: {
Supplier: { type: 'string', description: 'Supplier key (up to 10 characters)' },
AlternativePayeeAccountNumber: {
type: 'string',
description: 'Account number of the alternative payee',
optional: true,
},
AuthorizationGroup: {
type: 'string',
description: 'Authorization group',
optional: true,
},
BusinessPartner: {
type: 'string',
description: 'Linked BusinessPartner key',
optional: true,
},
BR_TaxIsSplit: {
type: 'boolean',
description: 'Brazil-specific tax split flag',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the supplier',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData v2 epoch)',
optional: true,
},
Customer: {
type: 'string',
description: 'Linked customer key (if any)',
optional: true,
},
DeletionIndicator: {
type: 'boolean',
description: 'Central deletion flag',
optional: true,
},
BirthDate: {
type: 'string',
description: 'Date of birth (OData v2 epoch)',
optional: true,
},
ConcatenatedInternationalLocNo: {
type: 'string',
description: 'Concatenated international location number',
optional: true,
},
FiscalAddress: {
type: 'string',
description: 'Fiscal address number',
optional: true,
},
Industry: { type: 'string', description: 'Industry key', optional: true },
InternationalLocationNumber1: {
type: 'string',
description: 'International location number, part 1',
optional: true,
},
InternationalLocationNumber2: {
type: 'string',
description: 'International location number, part 2',
optional: true,
},
InternationalLocationNumber3: {
type: 'string',
description: 'International location number, part 3',
optional: true,
},
IsNaturalPerson: {
type: 'boolean',
description: 'Indicates whether the supplier is a natural person',
optional: true,
},
PaymentIsBlockedForSupplier: {
type: 'boolean',
description: 'Payment block flag',
optional: true,
},
PostingIsBlocked: {
type: 'boolean',
description: 'Posting block flag',
optional: true,
},
PurchasingIsBlocked: {
type: 'boolean',
description: 'Purchasing block flag',
optional: true,
},
ResponsibleType: {
type: 'string',
description: 'Type of business (Brazil)',
optional: true,
},
SupplierAccountGroup: {
type: 'string',
description: 'Supplier account group',
optional: true,
},
SupplierCorporateGroup: {
type: 'string',
description: 'Corporate group identifier',
optional: true,
},
SupplierFullName: {
type: 'string',
description: 'Full name of the supplier',
optional: true,
},
SupplierName: { type: 'string', description: 'Supplier name', optional: true },
SupplierProcurementBlock: {
type: 'string',
description: 'Procurement block at supplier level',
optional: true,
},
SuplrProofOfDelivRlvtCode: {
type: 'string',
description: 'Proof of delivery relevance code',
optional: true,
},
SuplrQltyInProcmtCertfnValidTo: {
type: 'string',
description: 'Quality certification validity end date (OData v2 epoch)',
optional: true,
},
SuplrQualityManagementSystem: {
type: 'string',
description: 'Quality management system of the supplier',
optional: true,
},
TaxNumber1: { type: 'string', description: 'Tax number 1', optional: true },
TaxNumber2: { type: 'string', description: 'Tax number 2', optional: true },
TaxNumber3: { type: 'string', description: 'Tax number 3', optional: true },
TaxNumber4: { type: 'string', description: 'Tax number 4', optional: true },
TaxNumber5: { type: 'string', description: 'Tax number 5', optional: true },
TaxNumberResponsible: {
type: 'string',
description: 'Tax number of responsible party',
optional: true,
},
TaxNumberType: { type: 'string', description: 'Tax number type', optional: true },
VATRegistration: {
type: 'string',
description: 'VAT registration number',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,196 @@
import type { GetSupplierInvoiceParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildEntityQuery,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const getSupplierInvoiceTool: ToolConfig<GetSupplierInvoiceParams, SapProxyResponse> = {
id: 'sap_s4hana_get_supplier_invoice',
name: 'SAP S/4HANA Get Supplier Invoice',
description:
'Retrieve a single supplier invoice by composite key (SupplierInvoice + FiscalYear) from SAP S/4HANA Cloud (API_SUPPLIERINVOICE_PROCESS_SRV, A_SupplierInvoice).',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
supplierInvoice: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SupplierInvoice key (string, up to 10 characters)',
},
fiscalYear: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'FiscalYear (4-character year, e.g., "2024")',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand ($expand)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_SUPPLIERINVOICE_PROCESS_SRV',
path: `/A_SupplierInvoice(SupplierInvoice=${quoteOdataKey(params.supplierInvoice)},FiscalYear=${quoteOdataKey(params.fiscalYear)})`,
method: 'GET',
query: buildEntityQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'A_SupplierInvoice entity',
properties: {
SupplierInvoice: { type: 'string', description: 'Supplier invoice number' },
FiscalYear: { type: 'string', description: 'Fiscal year' },
CompanyCode: { type: 'string', description: 'Company code' },
DocumentDate: {
type: 'string',
description: 'Invoice document date',
optional: true,
},
PostingDate: { type: 'string', description: 'Posting date', optional: true },
InvoicingParty: {
type: 'string',
description: 'Invoicing party (supplier key)',
optional: true,
},
InvoiceGrossAmount: {
type: 'string',
description: 'Gross invoice amount',
optional: true,
},
DocumentCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
AccountingDocumentType: {
type: 'string',
description: 'Accounting document type',
optional: true,
},
PaymentTerms: {
type: 'string',
description: 'Payment terms key',
optional: true,
},
DueCalculationBaseDate: {
type: 'string',
description: 'Baseline date for due-date calculation',
optional: true,
},
SupplierInvoiceIDByInvcgParty: {
type: 'string',
description: 'Reference number used by the invoicing party',
optional: true,
},
PaymentMethod: {
type: 'string',
description: 'Payment method',
optional: true,
},
TaxIsCalculatedAutomatically: {
type: 'boolean',
description: 'Whether tax is calculated automatically',
optional: true,
},
ManualCashDiscount: {
type: 'string',
description: 'Manually entered cash discount amount',
optional: true,
},
BusinessPlace: {
type: 'string',
description: 'Business place (jurisdiction code)',
optional: true,
},
},
},
},
},
},
}
+38
View File
@@ -0,0 +1,38 @@
export { createBusinessPartnerTool } from '@/tools/sap_s4hana/create_business_partner'
export { createPurchaseOrderTool } from '@/tools/sap_s4hana/create_purchase_order'
export { createPurchaseRequisitionTool } from '@/tools/sap_s4hana/create_purchase_requisition'
export { createSalesOrderTool } from '@/tools/sap_s4hana/create_sales_order'
export { deleteSalesOrderTool } from '@/tools/sap_s4hana/delete_sales_order'
export { getBillingDocumentTool } from '@/tools/sap_s4hana/get_billing_document'
export { getBusinessPartnerTool } from '@/tools/sap_s4hana/get_business_partner'
export { getCustomerTool } from '@/tools/sap_s4hana/get_customer'
export { getInboundDeliveryTool } from '@/tools/sap_s4hana/get_inbound_delivery'
export { getMaterialDocumentTool } from '@/tools/sap_s4hana/get_material_document'
export { getOutboundDeliveryTool } from '@/tools/sap_s4hana/get_outbound_delivery'
export { getProductTool } from '@/tools/sap_s4hana/get_product'
export { getPurchaseOrderTool } from '@/tools/sap_s4hana/get_purchase_order'
export { getPurchaseRequisitionTool } from '@/tools/sap_s4hana/get_purchase_requisition'
export { getSalesOrderTool } from '@/tools/sap_s4hana/get_sales_order'
export { getSupplierTool } from '@/tools/sap_s4hana/get_supplier'
export { getSupplierInvoiceTool } from '@/tools/sap_s4hana/get_supplier_invoice'
export { listBillingDocumentsTool } from '@/tools/sap_s4hana/list_billing_documents'
export { listBusinessPartnersTool } from '@/tools/sap_s4hana/list_business_partners'
export { listCustomersTool } from '@/tools/sap_s4hana/list_customers'
export { listInboundDeliveriesTool } from '@/tools/sap_s4hana/list_inbound_deliveries'
export { listMaterialDocumentsTool } from '@/tools/sap_s4hana/list_material_documents'
export { listMaterialStockTool } from '@/tools/sap_s4hana/list_material_stock'
export { listOutboundDeliveriesTool } from '@/tools/sap_s4hana/list_outbound_deliveries'
export { listProductsTool } from '@/tools/sap_s4hana/list_products'
export { listPurchaseOrdersTool } from '@/tools/sap_s4hana/list_purchase_orders'
export { listPurchaseRequisitionsTool } from '@/tools/sap_s4hana/list_purchase_requisitions'
export { listSalesOrdersTool } from '@/tools/sap_s4hana/list_sales_orders'
export { listSupplierInvoicesTool } from '@/tools/sap_s4hana/list_supplier_invoices'
export { listSuppliersTool } from '@/tools/sap_s4hana/list_suppliers'
export { odataQueryTool } from '@/tools/sap_s4hana/odata_query'
export { updateBusinessPartnerTool } from '@/tools/sap_s4hana/update_business_partner'
export { updateCustomerTool } from '@/tools/sap_s4hana/update_customer'
export { updateProductTool } from '@/tools/sap_s4hana/update_product'
export { updatePurchaseOrderTool } from '@/tools/sap_s4hana/update_purchase_order'
export { updatePurchaseRequisitionTool } from '@/tools/sap_s4hana/update_purchase_requisition'
export { updateSalesOrderTool } from '@/tools/sap_s4hana/update_sales_order'
export { updateSupplierTool } from '@/tools/sap_s4hana/update_supplier'
@@ -0,0 +1,296 @@
import type { ListBillingDocumentsParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listBillingDocumentsTool: ToolConfig<ListBillingDocumentsParams, SapProxyResponse> = {
id: 'sap_s4hana_list_billing_documents',
name: 'SAP S/4HANA List Billing Documents',
description:
'List billing documents (customer invoices) from SAP S/4HANA Cloud (API_BILLING_DOCUMENT_SRV, A_BillingDocument) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "SoldToParty eq \'10100001\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_Item,to_Partner,to_PricingElement")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BILLING_DOCUMENT_SRV',
path: '/A_BillingDocument',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_BillingDocument entities',
items: {
type: 'object',
properties: {
BillingDocument: { type: 'string', description: 'Billing document number' },
SDDocumentCategory: {
type: 'string',
description: 'SD document category',
optional: true,
},
BillingDocumentCategory: {
type: 'string',
description: 'Billing document category',
optional: true,
},
BillingDocumentType: {
type: 'string',
description: 'Billing document type (e.g., F2)',
optional: true,
},
BillingDocumentDate: {
type: 'string',
description: 'Billing document date (OData /Date(ms)/)',
optional: true,
},
BillingDocumentIsCancelled: {
type: 'boolean',
description: 'Whether the billing document is cancelled',
optional: true,
},
CancelledBillingDocument: {
type: 'string',
description: 'Cancelled billing document number',
optional: true,
},
TotalNetAmount: {
type: 'string',
description: 'Total net amount (Edm.Decimal as string)',
optional: true,
},
TaxAmount: {
type: 'string',
description: 'Tax amount (Edm.Decimal as string)',
optional: true,
},
TotalGrossAmount: {
type: 'string',
description: 'Total gross amount (Edm.Decimal as string)',
optional: true,
},
TransactionCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
SoldToParty: {
type: 'string',
description: 'Sold-to business partner',
optional: true,
},
PayerParty: {
type: 'string',
description: 'Payer party',
optional: true,
},
SalesOrganization: {
type: 'string',
description: 'Sales organization',
optional: true,
},
DistributionChannel: {
type: 'string',
description: 'Distribution channel',
optional: true,
},
Division: { type: 'string', description: 'Division', optional: true },
CompanyCode: {
type: 'string',
description: 'Company code',
optional: true,
},
FiscalYear: { type: 'string', description: 'Fiscal year', optional: true },
OverallBillingStatus: {
type: 'string',
description: 'Overall billing status',
optional: true,
},
AccountingPostingStatus: {
type: 'string',
description: 'Accounting posting status',
optional: true,
},
AccountingTransferStatus: {
type: 'string',
description: 'Accounting transfer status',
optional: true,
},
InvoiceClearingStatus: {
type: 'string',
description: 'Invoice clearing status',
optional: true,
},
AccountingDocument: {
type: 'string',
description: 'Linked accounting document',
optional: true,
},
CustomerPaymentTerms: {
type: 'string',
description: 'Customer payment terms',
optional: true,
},
PaymentMethod: {
type: 'string',
description: 'Payment method',
optional: true,
},
DocumentReferenceID: {
type: 'string',
description: 'Document reference ID',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (OData /Date(ms)/)',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change date-time (Edm.DateTimeOffset)',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
__count: {
type: 'string',
description: 'Total count when $inlinecount=allpages is used',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,197 @@
import type { ListBusinessPartnersParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listBusinessPartnersTool: ToolConfig<ListBusinessPartnersParams, SapProxyResponse> = {
id: 'sap_s4hana_list_business_partners',
name: 'SAP S/4HANA List Business Partners',
description:
'List business partners from SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_BusinessPartner) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "BusinessPartnerCategory eq \'1\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand ($expand)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: '/A_BusinessPartner',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description:
'OData v2 envelope `{ d: { results: [...], __count?, __next? } }`. Properties listed below describe each element of `data.d.results`.',
properties: {
BusinessPartner: { type: 'string', description: 'Business partner key (up to 10 chars)' },
BusinessPartnerFullName: {
type: 'string',
description: 'Full name (concatenated first/last or organization name)',
optional: true,
},
BusinessPartnerCategory: {
type: 'string',
description: '"1" Person, "2" Organization, "3" Group',
optional: true,
},
BusinessPartnerGrouping: {
type: 'string',
description: 'Grouping / number range (tenant-configured)',
optional: true,
},
BusinessPartnerType: {
type: 'string',
description: 'Business partner type (tenant-configured)',
optional: true,
},
BusinessPartnerUUID: {
type: 'string',
description: 'GUID identifier for the business partner',
optional: true,
},
BusinessPartnerIsBlocked: {
type: 'boolean',
description: 'Whether the business partner is centrally blocked',
optional: true,
},
FirstName: { type: 'string', description: 'First name (Person)', optional: true },
LastName: { type: 'string', description: 'Last name (Person)', optional: true },
OrganizationBPName1: {
type: 'string',
description: 'Organization name line 1',
optional: true,
},
SearchTerm1: { type: 'string', description: 'Search term 1', optional: true },
CreationDate: {
type: 'string',
description: 'Date the partner was created (OData /Date(...)/ literal)',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the business partner',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Date of last change (OData /Date(...)/ literal)',
optional: true,
},
LastChangedByUser: {
type: 'string',
description: 'User who last changed the business partner',
optional: true,
},
},
},
},
}
+174
View File
@@ -0,0 +1,174 @@
import type { ListCustomersParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listCustomersTool: ToolConfig<ListCustomersParams, SapProxyResponse> = {
id: 'sap_s4hana_list_customers',
name: 'SAP S/4HANA List Customers',
description:
'List customers from SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_Customer) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "CustomerAccountGroup eq \'Z001\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_CustomerCompany,to_CustomerSalesArea")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: '/A_Customer',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description:
'Array of A_Customer entities, or `{ results, __count?, __next? }` when pagination metadata is present (proxy unwraps the OData v2 `d` envelope). Properties below describe each customer item.',
items: {
type: 'object',
properties: {
Customer: { type: 'string', description: 'Customer key (up to 10 characters)' },
CustomerName: { type: 'string', description: 'Name of customer' },
CustomerFullName: { type: 'string', description: 'Full name of the customer' },
CustomerAccountGroup: { type: 'string', description: 'Customer account group' },
CustomerClassification: { type: 'string', description: 'Customer classification code' },
CustomerCorporateGroup: { type: 'string', description: 'Corporate group code' },
AuthorizationGroup: { type: 'string', description: 'Authorization group' },
Supplier: { type: 'string', description: 'Linked supplier account number' },
FiscalAddress: { type: 'string', description: 'Fiscal address ID' },
Industry: { type: 'string', description: 'Industry key' },
NielsenRegion: { type: 'string', description: 'Nielsen ID' },
ResponsibleType: { type: 'string', description: 'Responsible type' },
NFPartnerIsNaturalPerson: { type: 'string', description: 'Natural person indicator' },
InternationalLocationNumber1: {
type: 'string',
description: 'International location number 1',
},
TaxNumberType: { type: 'string', description: 'Tax number type' },
VATRegistration: { type: 'string', description: 'VAT registration number' },
DeletionIndicator: { type: 'boolean', description: 'Central deletion flag' },
OrderIsBlockedForCustomer: {
type: 'string',
description: 'Central order block reason code',
},
PostingIsBlocked: { type: 'boolean', description: 'Central posting block flag' },
DeliveryIsBlocked: { type: 'string', description: 'Central delivery block reason code' },
BillingIsBlockedForCustomer: {
type: 'string',
description: 'Central billing block reason code',
},
CreationDate: { type: 'string', description: 'Creation date (OData v2 epoch)' },
CreatedByUser: { type: 'string', description: 'User who created the customer' },
},
},
},
},
}
@@ -0,0 +1,229 @@
import type { ListInboundDeliveriesParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listInboundDeliveriesTool: ToolConfig<ListInboundDeliveriesParams, SapProxyResponse> =
{
id: 'sap_s4hana_list_inbound_deliveries',
name: 'SAP S/4HANA List Inbound Deliveries',
description:
'List inbound deliveries from SAP S/4HANA Cloud (API_INBOUND_DELIVERY_SRV;v=0002, A_InbDeliveryHeader) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "ReceivingPlant eq \'1010\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_DeliveryDocumentItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_INBOUND_DELIVERY_SRV;v=0002',
path: '/A_InbDeliveryHeader',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_InbDeliveryHeader entities',
items: {
type: 'object',
properties: {
DeliveryDocument: { type: 'string', description: 'Inbound delivery number' },
DeliveryDocumentType: {
type: 'string',
description: 'Delivery document type (e.g., EL)',
},
SDDocumentCategory: {
type: 'string',
description: 'SD document category (e.g., 7 = inbound delivery)',
optional: true,
},
ReceivingPlant: {
type: 'string',
description: 'Receiving plant',
optional: true,
},
Supplier: {
type: 'string',
description: 'Supplier business partner',
optional: true,
},
ShipToParty: {
type: 'string',
description: 'Ship-to business partner',
optional: true,
},
DeliveryDate: {
type: 'string',
description: 'Delivery date (Edm.DateTime)',
optional: true,
},
ActualGoodsMovementDate: {
type: 'string',
description: 'Actual goods movement (receipt) date (Edm.DateTime)',
optional: true,
},
PlannedGoodsMovementDate: {
type: 'string',
description: 'Planned goods movement date (Edm.DateTime)',
optional: true,
},
OverallSDProcessStatus: {
type: 'string',
description: 'Overall SD process (delivery) status',
optional: true,
},
OverallGoodsMovementStatus: {
type: 'string',
description: 'Overall goods movement status',
optional: true,
},
DocumentDate: {
type: 'string',
description: 'Document date (Edm.DateTime)',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (Edm.DateTime)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (Edm.DateTime)',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
__count: {
type: 'string',
description: 'Total count when $inlinecount=allpages is used',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,193 @@
import type { ListMaterialDocumentsParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listMaterialDocumentsTool: ToolConfig<ListMaterialDocumentsParams, SapProxyResponse> =
{
id: 'sap_s4hana_list_material_documents',
name: 'SAP S/4HANA List Material Documents',
description:
'List material document headers (goods movements) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
"OData $filter expression (e.g., \"MaterialDocumentYear eq '2024' and PostingDate ge datetime'2024-01-01T00:00:00'\")",
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_MaterialDocumentItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_MATERIAL_DOCUMENT_SRV',
path: '/A_MaterialDocumentHeader',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData payload containing the array of A_MaterialDocumentHeader entities',
properties: {
MaterialDocumentYear: {
type: 'string',
description: 'Material document year (4-digit fiscal year)',
},
MaterialDocument: { type: 'string', description: 'Material document number' },
DocumentDate: { type: 'string', description: 'Document date (OData /Date(...)/ string)' },
PostingDate: { type: 'string', description: 'Posting date (OData /Date(...)/ string)' },
MaterialDocumentHeaderText: {
type: 'string',
description: 'Header text describing the material document',
optional: true,
},
ReferenceDocument: {
type: 'string',
description: 'Reference document number',
optional: true,
},
GoodsMovementCode: {
type: 'string',
description: 'Goods movement code (e.g., 01 GR for PO, 03 GI to cost center)',
},
InventoryTransactionType: {
type: 'string',
description: 'Inventory transaction type indicator',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the material document',
},
CreationDate: { type: 'string', description: 'Creation date (OData /Date(...)/ string)' },
CreationTime: { type: 'string', description: 'Creation time (OData PT...S string)' },
VersionForPrintingSlip: {
type: 'string',
description: 'Version for printing the goods movement slip',
optional: true,
},
ManualPrintIsTriggered: {
type: 'boolean',
description: 'Indicates whether manual print was triggered for this document',
optional: true,
},
CtrlPostgForExtWhseMgmtSyst: {
type: 'string',
description: 'Control posting for external warehouse management system',
optional: true,
},
to_MaterialDocumentItem: {
type: 'json',
description:
'Material document items (only present when $expand=to_MaterialDocumentItem is supplied)',
optional: true,
},
},
},
},
}
@@ -0,0 +1,179 @@
import type { ListMaterialStockParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listMaterialStockTool: ToolConfig<ListMaterialStockParams, SapProxyResponse> = {
id: 'sap_s4hana_list_material_stock',
name: 'SAP S/4HANA List Material Stock',
description:
'List material stock quantities from SAP S/4HANA Cloud (API_MATERIAL_STOCK_SRV, A_MatlStkInAcctMod). The entity uses an 11-field composite key (Material, Plant, StorageLocation, Batch, Supplier, Customer, WBSElementInternalID, SDDocument, SDDocumentItem, InventorySpecialStockType, InventoryStockType) — query with $filter on these fields instead of a direct key lookup.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
"OData $filter expression (e.g., \"Material eq 'TG10' and Plant eq '1010' and InventoryStockType eq '01'\")",
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand ($expand)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_MATERIAL_STOCK_SRV',
path: '/A_MatlStkInAcctMod',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData payload containing the array of A_MatlStkInAcctMod stock entries',
properties: {
Material: { type: 'string', description: 'Material number' },
Plant: { type: 'string', description: 'Plant identifier' },
StorageLocation: {
type: 'string',
description: 'Storage location identifier',
optional: true,
},
Batch: { type: 'string', description: 'Batch identifier', optional: true },
Supplier: {
type: 'string',
description: 'Supplier business partner key',
optional: true,
},
Customer: {
type: 'string',
description: 'Customer business partner key',
optional: true,
},
WBSElementInternalID: {
type: 'string',
description: 'WBS element internal ID',
optional: true,
},
SDDocument: { type: 'string', description: 'SD document number', optional: true },
SDDocumentItem: { type: 'string', description: 'SD document item', optional: true },
InventorySpecialStockType: {
type: 'string',
description: 'Special stock type indicator',
optional: true,
},
InventoryStockType: {
type: 'string',
description:
'Stock type (e.g., 01 unrestricted-use, 02 quality inspection, 03 blocked, 04 restricted-use)',
},
MatlWrhsStkQtyInMatlBaseUnit: {
type: 'string',
description:
'Material warehouse stock quantity in material base unit (Edm.Decimal serialized as string)',
},
MaterialBaseUnit: { type: 'string', description: 'Material base unit of measure' },
},
},
},
}
@@ -0,0 +1,241 @@
import type { ListOutboundDeliveriesParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listOutboundDeliveriesTool: ToolConfig<
ListOutboundDeliveriesParams,
SapProxyResponse
> = {
id: 'sap_s4hana_list_outbound_deliveries',
name: 'SAP S/4HANA List Outbound Deliveries',
description:
'List outbound deliveries from SAP S/4HANA Cloud (API_OUTBOUND_DELIVERY_SRV;v=0002, A_OutbDeliveryHeader) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "OverallDeliveryStatus eq \'C\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_DeliveryDocumentItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_OUTBOUND_DELIVERY_SRV;v=0002',
path: '/A_OutbDeliveryHeader',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_OutbDeliveryHeader entities',
items: {
type: 'object',
properties: {
DeliveryDocument: { type: 'string', description: 'Outbound delivery number' },
DeliveryDocumentType: {
type: 'string',
description: 'Delivery document type (e.g., LF)',
},
SDDocumentCategory: {
type: 'string',
description: 'SD document category (e.g., J = outbound delivery)',
optional: true,
},
ShippingPoint: {
type: 'string',
description: 'Shipping point',
optional: true,
},
ShippingType: {
type: 'string',
description: 'Shipping type',
optional: true,
},
ShipToParty: {
type: 'string',
description: 'Ship-to business partner',
optional: true,
},
SoldToParty: {
type: 'string',
description: 'Sold-to business partner',
optional: true,
},
DeliveryDate: {
type: 'string',
description: 'Delivery date (Edm.DateTime)',
optional: true,
},
ActualGoodsMovementDate: {
type: 'string',
description: 'Actual goods issue date (Edm.DateTime)',
optional: true,
},
PlannedGoodsIssueDate: {
type: 'string',
description: 'Planned goods issue date (Edm.DateTime)',
optional: true,
},
OverallSDProcessStatus: {
type: 'string',
description: 'Overall SD process (delivery) status',
optional: true,
},
OverallGoodsMovementStatus: {
type: 'string',
description: 'Overall goods movement status',
optional: true,
},
TransactionCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
DocumentDate: {
type: 'string',
description: 'Document date (Edm.DateTime)',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (Edm.DateTime)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (Edm.DateTime)',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
__count: {
type: 'string',
description: 'Total count when $inlinecount=allpages is used',
optional: true,
},
},
},
},
},
},
}
+249
View File
@@ -0,0 +1,249 @@
import type { ListProductsParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listProductsTool: ToolConfig<ListProductsParams, SapProxyResponse> = {
id: 'sap_s4hana_list_products',
name: 'SAP S/4HANA List Products',
description:
'List products (materials) from SAP S/4HANA Cloud (API_PRODUCT_SRV, A_Product) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "ProductType eq \'FERT\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand ($expand)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_PRODUCT_SRV',
path: '/A_Product',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_Product entities',
items: {
type: 'object',
properties: {
Product: {
type: 'string',
description: 'Product (material) number',
optional: true,
},
ProductType: {
type: 'string',
description: 'Product type (e.g., FERT, HAWA)',
optional: true,
},
ProductGroup: {
type: 'string',
description: 'Material group',
optional: true,
},
BaseUnit: {
type: 'string',
description: 'Base unit of measure',
optional: true,
},
Brand: { type: 'string', description: 'Brand', optional: true },
Division: { type: 'string', description: 'Division', optional: true },
GrossWeight: {
type: 'string',
description: 'Gross weight',
optional: true,
},
NetWeight: {
type: 'string',
description: 'Net weight',
optional: true,
},
WeightUnit: {
type: 'string',
description: 'Weight unit of measure',
optional: true,
},
CrossPlantStatus: {
type: 'string',
description: 'Cross-plant material status',
optional: true,
},
IsMarkedForDeletion: {
type: 'boolean',
description: 'Deletion flag',
optional: true,
},
ProductStandardID: {
type: 'string',
description: 'Standard product ID (e.g., GTIN)',
optional: true,
},
ItemCategoryGroup: {
type: 'string',
description: 'Item category group',
optional: true,
},
ProductOldID: {
type: 'string',
description: 'Legacy/old product ID',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the product',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
LastChangedByUser: {
type: 'string',
description: 'User who last changed the product',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change timestamp (Edm.DateTimeOffset)',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
__count: {
type: 'string',
description: 'Total count when $inlinecount=allpages is used',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,199 @@
import type { ListPurchaseOrdersParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listPurchaseOrdersTool: ToolConfig<ListPurchaseOrdersParams, SapProxyResponse> = {
id: 'sap_s4hana_list_purchase_orders',
name: 'SAP S/4HANA List Purchase Orders',
description:
'List purchase orders from SAP S/4HANA Cloud (API_PURCHASEORDER_PROCESS_SRV, A_PurchaseOrder) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "CompanyCode eq \'1010\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_PurchaseOrderItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_PURCHASEORDER_PROCESS_SRV',
path: '/A_PurchaseOrder',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_PurchaseOrder entities',
items: {
type: 'object',
properties: {
PurchaseOrder: { type: 'string', description: 'Purchase order number' },
PurchaseOrderType: {
type: 'string',
description: 'PO document type (e.g., NB)',
},
CompanyCode: { type: 'string', description: 'Company code' },
PurchasingOrganization: {
type: 'string',
description: 'Purchasing organization',
},
PurchasingGroup: { type: 'string', description: 'Purchasing group' },
Supplier: { type: 'string', description: 'Supplier business partner key' },
DocumentCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
NetAmount: {
type: 'string',
description: 'Net amount of the purchase order',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData /Date(ms)/)',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the PO',
optional: true,
},
PurchaseOrderDate: {
type: 'string',
description: 'Purchase order date',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
__count: {
type: 'string',
description: 'Total count when $inlinecount=allpages is used',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,178 @@
import type { ListPurchaseRequisitionsParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listPurchaseRequisitionsTool: ToolConfig<
ListPurchaseRequisitionsParams,
SapProxyResponse
> = {
id: 'sap_s4hana_list_purchase_requisitions',
name: 'SAP S/4HANA List Purchase Requisitions',
description:
'List purchase requisitions from SAP S/4HANA Cloud (API_PURCHASEREQ_PROCESS_SRV, A_PurchaseRequisitionHeader) with optional OData $filter, $top, $skip, $orderby, $select, $expand. Note: API_PURCHASEREQ_PROCESS_SRV is deprecated since S/4HANA Cloud Public Edition 2402; the successor is API_PURCHASEREQUISITION_2 (OData v4). This tool still works against tenants where the legacy service is enabled.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "PurchaseRequisitionType eq \'NB\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_PurchaseReqnItem")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_PURCHASEREQ_PROCESS_SRV',
path: '/A_PurchaseRequisitionHeader',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_PurchaseRequisitionHeader entities',
items: {
type: 'object',
properties: {
PurchaseRequisition: {
type: 'string',
description: 'Purchase requisition number',
},
PurchaseRequisitionType: {
type: 'string',
description: 'Purchase requisition document type (e.g., NB)',
},
PurReqnDescription: {
type: 'string',
description: 'Purchase requisition description',
optional: true,
},
SourceDetermination: {
type: 'string',
description: 'Source-of-supply determination flag',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,201 @@
import type { ListSalesOrdersParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listSalesOrdersTool: ToolConfig<ListSalesOrdersParams, SapProxyResponse> = {
id: 'sap_s4hana_list_sales_orders',
name: 'SAP S/4HANA List Sales Orders',
description:
'List sales orders from SAP S/4HANA Cloud (API_SALES_ORDER_SRV, A_SalesOrder) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "SalesOrganization eq \'1010\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand (e.g., "to_Item,to_Partner")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_SALES_ORDER_SRV',
path: '/A_SalesOrder',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_SalesOrder entities',
items: {
type: 'object',
properties: {
SalesOrder: { type: 'string', description: 'Sales order number' },
SalesOrderType: { type: 'string', description: 'Sales document type (e.g., OR)' },
SalesOrganization: { type: 'string', description: 'Sales organization' },
DistributionChannel: { type: 'string', description: 'Distribution channel' },
OrganizationDivision: { type: 'string', description: 'Division' },
SoldToParty: { type: 'string', description: 'Sold-to business partner' },
TotalNetAmount: { type: 'string', description: 'Total net amount' },
TransactionCurrency: { type: 'string', description: 'Document currency' },
CreationDate: { type: 'string', description: 'Creation date (OData /Date(ms)/)' },
SalesOrderDate: {
type: 'string',
description: 'Sales order date (OData /Date(ms)/)',
optional: true,
},
RequestedDeliveryDate: {
type: 'string',
description: 'Requested delivery date (OData /Date(ms)/)',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date (OData /Date(ms)/)',
optional: true,
},
PurchaseOrderByCustomer: {
type: 'string',
description: 'Customer purchase order reference',
optional: true,
},
OverallSDProcessStatus: {
type: 'string',
description: 'Overall sales document process status',
optional: true,
},
OverallTotalDeliveryStatus: {
type: 'string',
description: 'Overall total delivery status',
optional: true,
},
OverallSDDocumentRejectionSts: {
type: 'string',
description: 'Overall sales document rejection status',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,225 @@
import type { ListSupplierInvoicesParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listSupplierInvoicesTool: ToolConfig<ListSupplierInvoicesParams, SapProxyResponse> = {
id: 'sap_s4hana_list_supplier_invoices',
name: 'SAP S/4HANA List Supplier Invoices',
description:
'List supplier invoices from SAP S/4HANA Cloud (API_SUPPLIERINVOICE_PROCESS_SRV, A_SupplierInvoice) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "InvoicingParty eq \'17300001\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated navigation properties to expand ($expand)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_SUPPLIERINVOICE_PROCESS_SRV',
path: '/A_SupplierInvoice',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_SupplierInvoice entities',
items: {
type: 'object',
properties: {
SupplierInvoice: { type: 'string', description: 'Supplier invoice number' },
FiscalYear: { type: 'string', description: 'Fiscal year' },
CompanyCode: { type: 'string', description: 'Company code' },
DocumentDate: {
type: 'string',
description: 'Invoice document date',
optional: true,
},
PostingDate: {
type: 'string',
description: 'Posting date',
optional: true,
},
InvoicingParty: {
type: 'string',
description: 'Invoicing party (supplier key)',
optional: true,
},
InvoiceGrossAmount: {
type: 'string',
description: 'Gross invoice amount',
optional: true,
},
DocumentCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
AccountingDocumentType: {
type: 'string',
description: 'Accounting document type',
optional: true,
},
PaymentTerms: {
type: 'string',
description: 'Payment terms key',
optional: true,
},
DueCalculationBaseDate: {
type: 'string',
description: 'Baseline date for due-date calculation',
optional: true,
},
SupplierInvoiceIDByInvcgParty: {
type: 'string',
description: 'Reference number used by the invoicing party',
optional: true,
},
PaymentMethod: {
type: 'string',
description: 'Payment method',
optional: true,
},
TaxIsCalculatedAutomatically: {
type: 'boolean',
description: 'Whether tax is calculated automatically',
optional: true,
},
ManualCashDiscount: {
type: 'string',
description: 'Manually entered cash discount amount',
optional: true,
},
BusinessPlace: {
type: 'string',
description: 'Business place (jurisdiction code)',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
},
},
},
},
},
}
+311
View File
@@ -0,0 +1,311 @@
import type { ListSuppliersParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
buildOdataQuery,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const listSuppliersTool: ToolConfig<ListSuppliersParams, SapProxyResponse> = {
id: 'sap_s4hana_list_suppliers',
name: 'SAP S/4HANA List Suppliers',
description:
'List suppliers from SAP S/4HANA Cloud (API_BUSINESS_PARTNER, A_Supplier) with optional OData $filter, $top, $skip, $orderby, $select, $expand.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $filter expression (e.g., "SupplierAccountGroup eq \'BP02\'")',
},
top: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum results to return ($top)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip ($skip)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'OData $orderby expression',
},
select: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated fields to return ($select)',
},
expand: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated navigation properties to expand (e.g., "to_SupplierCompany,to_SupplierPurchasingOrg")',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: '/A_Supplier',
method: 'GET',
query: buildOdataQuery(params),
}),
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'OData v2 response envelope; collection at output.data.d.results',
properties: {
d: {
type: 'json',
description: 'OData v2 envelope',
properties: {
results: {
type: 'array',
description: 'A_Supplier entities',
items: {
type: 'object',
properties: {
Supplier: { type: 'string', description: 'Supplier key (up to 10 characters)' },
AlternativePayeeAccountNumber: {
type: 'string',
description: 'Account number of the alternative payee',
optional: true,
},
AuthorizationGroup: {
type: 'string',
description: 'Authorization group',
optional: true,
},
BusinessPartner: {
type: 'string',
description: 'Linked BusinessPartner key',
optional: true,
},
BR_TaxIsSplit: {
type: 'boolean',
description: 'Brazil-specific tax split flag',
optional: true,
},
CreatedByUser: {
type: 'string',
description: 'User who created the supplier',
optional: true,
},
CreationDate: {
type: 'string',
description: 'Creation date (OData v2 epoch)',
optional: true,
},
Customer: {
type: 'string',
description: 'Linked customer key (if any)',
optional: true,
},
DeletionIndicator: {
type: 'boolean',
description: 'Central deletion flag',
optional: true,
},
BirthDate: {
type: 'string',
description: 'Date of birth (OData v2 epoch)',
optional: true,
},
ConcatenatedInternationalLocNo: {
type: 'string',
description: 'Concatenated international location number',
optional: true,
},
FiscalAddress: {
type: 'string',
description: 'Fiscal address number',
optional: true,
},
Industry: { type: 'string', description: 'Industry key', optional: true },
InternationalLocationNumber1: {
type: 'string',
description: 'International location number, part 1',
optional: true,
},
InternationalLocationNumber2: {
type: 'string',
description: 'International location number, part 2',
optional: true,
},
InternationalLocationNumber3: {
type: 'string',
description: 'International location number, part 3',
optional: true,
},
IsNaturalPerson: {
type: 'boolean',
description: 'Indicates whether the supplier is a natural person',
optional: true,
},
PaymentIsBlockedForSupplier: {
type: 'boolean',
description: 'Payment block flag',
optional: true,
},
PostingIsBlocked: {
type: 'boolean',
description: 'Posting block flag',
optional: true,
},
PurchasingIsBlocked: {
type: 'boolean',
description: 'Purchasing block flag',
optional: true,
},
ResponsibleType: {
type: 'string',
description: 'Type of business (Brazil)',
optional: true,
},
SupplierAccountGroup: {
type: 'string',
description: 'Supplier account group',
optional: true,
},
SupplierCorporateGroup: {
type: 'string',
description: 'Corporate group identifier',
optional: true,
},
SupplierFullName: {
type: 'string',
description: 'Full name of the supplier',
optional: true,
},
SupplierName: { type: 'string', description: 'Supplier name', optional: true },
SupplierProcurementBlock: {
type: 'string',
description: 'Procurement block at supplier level',
optional: true,
},
SuplrProofOfDelivRlvtCode: {
type: 'string',
description: 'Proof of delivery relevance code',
optional: true,
},
SuplrQltyInProcmtCertfnValidTo: {
type: 'string',
description: 'Quality certification validity end date (OData v2 epoch)',
optional: true,
},
SuplrQualityManagementSystem: {
type: 'string',
description: 'Quality management system of the supplier',
optional: true,
},
TaxNumber1: { type: 'string', description: 'Tax number 1', optional: true },
TaxNumber2: { type: 'string', description: 'Tax number 2', optional: true },
TaxNumber3: { type: 'string', description: 'Tax number 3', optional: true },
TaxNumber4: { type: 'string', description: 'Tax number 4', optional: true },
TaxNumber5: { type: 'string', description: 'Tax number 5', optional: true },
TaxNumberResponsible: {
type: 'string',
description: 'Tax number of responsible party',
optional: true,
},
TaxNumberType: {
type: 'string',
description: 'Tax number type',
optional: true,
},
VATRegistration: {
type: 'string',
description: 'VAT registration number',
optional: true,
},
},
},
},
__next: {
type: 'string',
description: 'OData skiptoken URL for next page',
optional: true,
},
},
},
},
},
},
}
+163
View File
@@ -0,0 +1,163 @@
import type { ODataQueryParams, SapProxyResponse } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
function normalizeQuery(
query: ODataQueryParams['query']
): Record<string, string | number | boolean> | undefined {
if (!query) return undefined
if (typeof query === 'object') return query
if (typeof query !== 'string') return undefined
const trimmed = query.trim()
if (!trimmed) return undefined
if (trimmed.startsWith('{')) {
return parseJsonInput<Record<string, string | number | boolean>>(trimmed, 'query')
}
const search = new URLSearchParams(trimmed.startsWith('?') ? trimmed.slice(1) : trimmed)
const result: Record<string, string> = {}
for (const [key, value] of search.entries()) result[key] = value
return result
}
export const odataQueryTool: ToolConfig<ODataQueryParams, SapProxyResponse> = {
id: 'sap_s4hana_odata_query',
name: 'SAP S/4HANA OData Query',
description:
'Make an arbitrary OData v2 call against any SAP S/4HANA Cloud whitelisted Communication Scenario. Use when no dedicated tool exists for the entity. The proxy handles auth, CSRF, and OData unwrapping. For write operations (POST/PUT/PATCH/MERGE/DELETE), pass an If-Match ETag obtained from a prior GET to avoid lost updates; misuse will mutate production data.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
service: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'OData service name (e.g., "API_BUSINESS_PARTNER", "API_SALES_ORDER_SRV")',
},
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Path inside the service (e.g., "/A_BusinessPartner" or "/A_BusinessPartner(\'1000123\')")',
},
method: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'HTTP method: GET (default), POST, PATCH, PUT, DELETE, MERGE',
},
query: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description:
'OData query parameters as JSON object or query string (e.g., {"$filter":"BusinessPartnerCategory eq \'1\'","$top":10}). $format=json is added automatically when omitted.',
},
body: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'JSON request body for write operations',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'ETag value for the If-Match header (required by SAP for PATCH/PUT/DELETE on existing entities)',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const query = normalizeQuery(params.query) ?? {}
if (!('$format' in query)) query.$format = 'json'
const requestBody: Record<string, unknown> = {
...baseProxyBody(params),
service: params.service,
path: params.path,
method: params.method || 'GET',
query,
}
const parsedBody = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (parsedBody !== undefined) requestBody.body = parsedBody
if (params.ifMatch) requestBody.ifMatch = params.ifMatch
return requestBody
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP' },
data: {
type: 'json',
description: 'Parsed OData payload (entity, collection, or null on 204)',
},
},
}
+309
View File
@@ -0,0 +1,309 @@
import type { ToolResponse } from '@/tools/types'
export type SapDeploymentType = 'cloud_public' | 'cloud_private' | 'on_premise'
export type SapAuthType = 'oauth_client_credentials' | 'basic'
export interface SapBaseParams {
deploymentType?: SapDeploymentType
authType?: SapAuthType
subdomain?: string
region?: string
baseUrl?: string
tokenUrl?: string
clientId?: string
clientSecret?: string
username?: string
password?: string
}
interface ProxyOutput {
status: number
data: unknown
}
export interface SapProxyResponse extends ToolResponse {
output: ProxyOutput
}
export interface ListBusinessPartnersParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetBusinessPartnerParams extends SapBaseParams {
businessPartner: string
select?: string
expand?: string
}
export interface CreateBusinessPartnerParams extends SapBaseParams {
businessPartnerCategory: string
businessPartnerGrouping: string
firstName?: string
lastName?: string
organizationBPName1?: string
body?: Record<string, unknown> | string
}
export interface ListSalesOrdersParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetSalesOrderParams extends SapBaseParams {
salesOrder: string
select?: string
expand?: string
}
export interface CreateSalesOrderParams extends SapBaseParams {
salesOrderType: string
salesOrganization: string
distributionChannel: string
organizationDivision: string
soldToParty: string
items: string | Array<Record<string, unknown>>
body?: Record<string, unknown> | string
}
export interface ListProductsParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetProductParams extends SapBaseParams {
product: string
select?: string
expand?: string
}
export interface ListPurchaseOrdersParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetPurchaseOrderParams extends SapBaseParams {
purchaseOrder: string
select?: string
expand?: string
}
export interface CreatePurchaseOrderParams extends SapBaseParams {
purchaseOrderType: string
companyCode: string
purchasingOrganization: string
purchasingGroup: string
supplier: string
body: Record<string, unknown> | string
}
export interface ListSupplierInvoicesParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetSupplierInvoiceParams extends SapBaseParams {
supplierInvoice: string
fiscalYear: string
select?: string
expand?: string
}
export interface ListOutboundDeliveriesParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetOutboundDeliveryParams extends SapBaseParams {
deliveryDocument: string
select?: string
expand?: string
}
export interface ListBillingDocumentsParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetBillingDocumentParams extends SapBaseParams {
billingDocument: string
select?: string
expand?: string
}
export interface ListPurchaseRequisitionsParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetPurchaseRequisitionParams extends SapBaseParams {
purchaseRequisition: string
select?: string
expand?: string
}
export interface ListMaterialStockParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface ListSuppliersParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetSupplierParams extends SapBaseParams {
supplier: string
select?: string
expand?: string
}
export interface ListCustomersParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetCustomerParams extends SapBaseParams {
customer: string
select?: string
expand?: string
}
export interface ListInboundDeliveriesParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface GetInboundDeliveryParams extends SapBaseParams {
deliveryDocument: string
select?: string
expand?: string
}
export interface GetMaterialDocumentParams extends SapBaseParams {
materialDocumentYear: string
materialDocument: string
select?: string
expand?: string
}
export interface ListMaterialDocumentsParams extends SapBaseParams {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}
export interface UpdateBusinessPartnerParams extends SapBaseParams {
businessPartner: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface UpdateCustomerParams extends SapBaseParams {
customer: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface UpdateSupplierParams extends SapBaseParams {
supplier: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface UpdateProductParams extends SapBaseParams {
product: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface UpdateSalesOrderParams extends SapBaseParams {
salesOrder: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface DeleteSalesOrderParams extends SapBaseParams {
salesOrder: string
ifMatch?: string
}
export interface UpdatePurchaseOrderParams extends SapBaseParams {
purchaseOrder: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface UpdatePurchaseRequisitionParams extends SapBaseParams {
purchaseRequisition: string
body: Record<string, unknown> | string
ifMatch?: string
}
export interface CreatePurchaseRequisitionParams extends SapBaseParams {
purchaseRequisitionType: string
items: string | Array<Record<string, unknown>>
body?: Record<string, unknown> | string
}
export type ODataMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' | 'MERGE'
export interface ODataQueryParams extends SapBaseParams {
service: string
path: string
method?: ODataMethod
query?: string | Record<string, string | number | boolean>
body?: Record<string, unknown> | string
ifMatch?: string
}
@@ -0,0 +1,167 @@
import type { SapProxyResponse, UpdateBusinessPartnerParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updateBusinessPartnerTool: ToolConfig<UpdateBusinessPartnerParams, SapProxyResponse> =
{
id: 'sap_s4hana_update_business_partner',
name: 'SAP S/4HANA Update Business Partner',
description:
'Update fields on an A_BusinessPartner entity in SAP S/4HANA Cloud (API_BUSINESS_PARTNER). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. If-Match defaults to a wildcard (unconditional) — for safe concurrent updates pass the ETag from a prior GET to avoid lost updates. Deep updates on nested associations (e.g. to_BusinessPartnerAddress) are not supported by SAP (KBA 2833338) — use the dedicated child endpoints.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
businessPartner: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'BusinessPartner key to update (string, up to 10 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_BusinessPartner fields to update (e.g., {"FirstName":"Jane","SearchTerm1":"VIP"})',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: `/A_BusinessPartner(${quoteOdataKey(params.businessPartner)})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description: 'Null on 204 success, or updated A_BusinessPartner entity if SAP returns one',
properties: {
BusinessPartner: {
type: 'string',
description: 'Business partner key',
optional: true,
},
BusinessPartnerFullName: {
type: 'string',
description: 'Full name (concatenated first/last or organization name)',
optional: true,
},
BusinessPartnerCategory: {
type: 'string',
description: '"1" Person, "2" Organization, "3" Group',
optional: true,
},
BusinessPartnerGrouping: {
type: 'string',
description: 'Grouping / number range',
optional: true,
},
FirstName: { type: 'string', description: 'First name (Person)', optional: true },
LastName: { type: 'string', description: 'Last name (Person)', optional: true },
OrganizationBPName1: {
type: 'string',
description: 'Organization name line 1',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Date of last change (OData /Date(...)/ literal)',
optional: true,
},
LastChangedByUser: {
type: 'string',
description: 'User who last changed the business partner',
optional: true,
},
},
},
},
}
@@ -0,0 +1,143 @@
import type { SapProxyResponse, UpdateCustomerParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updateCustomerTool: ToolConfig<UpdateCustomerParams, SapProxyResponse> = {
id: 'sap_s4hana_update_customer',
name: 'SAP S/4HANA Update Customer',
description:
'Update fields on an A_Customer entity in SAP S/4HANA Cloud (API_BUSINESS_PARTNER). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. A_Customer is limited to modifiable fields such as OrderIsBlockedForCustomer, DeliveryIsBlocked, BillingIsBlockedForCustomer (Edm.String reason codes like "01"), PostingIsBlocked, and DeletionIndicator (Edm.Boolean). If-Match defaults to a wildcard - for safe concurrent updates pass the ETag from a prior GET to avoid lost updates.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
customer: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Customer key to update (string, up to 10 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_Customer fields to update (e.g., {"OrderIsBlockedForCustomer":"01","DeletionIndicator":false}). Block-reason fields are Edm.String codes, not booleans.',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: `/A_Customer(${quoteOdataKey(params.customer)})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'object',
description: 'Null on 204 success, or updated A_Customer entity if SAP returns one',
properties: {
Customer: { type: 'string', description: 'Customer key (up to 10 characters)' },
CustomerName: { type: 'string', description: 'Name of customer' },
CustomerAccountGroup: { type: 'string', description: 'Customer account group' },
DeletionIndicator: { type: 'boolean', description: 'Central deletion flag' },
OrderIsBlockedForCustomer: {
type: 'string',
description: 'Central order block reason code',
},
PostingIsBlocked: { type: 'boolean', description: 'Central posting block flag' },
DeliveryIsBlocked: { type: 'string', description: 'Central delivery block reason code' },
BillingIsBlockedForCustomer: {
type: 'string',
description: 'Central billing block reason code',
},
},
},
},
}
+151
View File
@@ -0,0 +1,151 @@
import type { SapProxyResponse, UpdateProductParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updateProductTool: ToolConfig<UpdateProductParams, SapProxyResponse> = {
id: 'sap_s4hana_update_product',
name: 'SAP S/4HANA Update Product',
description:
'Update fields on an A_Product entity in SAP S/4HANA Cloud (API_PRODUCT_SRV). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. Flat scalar header fields only — deep/multi-entity updates across navigation properties are not supported by API_PRODUCT_SRV MERGE/PUT (see SAP KBA 2833338); update child entities (plant, valuation, sales data, etc.) via their own endpoints. If-Match defaults to a wildcard (unconditional) — for safe concurrent updates pass the ETag from a prior GET.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
product: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Product key to update (string, up to 40 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_Product fields to update (e.g., {"ProductGroup":"L001","IsMarkedForDeletion":false})',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_PRODUCT_SRV',
path: `/A_Product(${quoteOdataKey(params.product)})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description:
'Null on 204 success, or OData v2 envelope with the updated A_Product entity at output.data.d',
properties: {
d: {
type: 'json',
description: 'Updated A_Product entity (only present if SAP returns a body)',
optional: true,
properties: {
Product: { type: 'string', description: 'Product (material) number' },
ProductType: { type: 'string', description: 'Product type', optional: true },
ProductGroup: { type: 'string', description: 'Material group', optional: true },
BaseUnit: { type: 'string', description: 'Base unit of measure', optional: true },
IsMarkedForDeletion: {
type: 'boolean',
description: 'Deletion flag',
optional: true,
},
LastChangeDate: {
type: 'string',
description: 'Last change date',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,161 @@
import type { SapProxyResponse, UpdatePurchaseOrderParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updatePurchaseOrderTool: ToolConfig<UpdatePurchaseOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_update_purchase_order',
name: 'SAP S/4HANA Update Purchase Order',
description:
'Update fields on an A_PurchaseOrder header in SAP S/4HANA Cloud (API_PURCHASEORDER_PROCESS_SRV). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. Header-only — line-item changes are not supported via deep update on the header (SAP KBA 2833338); use the A_PurchaseOrderItem entity directly to modify items. If-Match defaults to a wildcard - for safe concurrent updates pass the ETag from a prior GET to avoid lost updates.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
purchaseOrder: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchaseOrder key to update (string, up to 10 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_PurchaseOrder fields to update (e.g., {"PurchasingGroup":"002","PurchaseOrderDate":"/Date(1735689600000)/"})',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_PURCHASEORDER_PROCESS_SRV',
path: `/A_PurchaseOrder(${quoteOdataKey(params.purchaseOrder.trim())})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description:
'Null on 204 success, or OData v2 envelope with updated A_PurchaseOrder at output.data.d',
properties: {
d: {
type: 'json',
description: 'Updated A_PurchaseOrder entity (if returned)',
optional: true,
properties: {
PurchaseOrder: {
type: 'string',
description: 'Purchase order number',
optional: true,
},
PurchaseOrderType: {
type: 'string',
description: 'PO document type',
optional: true,
},
CompanyCode: { type: 'string', description: 'Company code', optional: true },
PurchasingGroup: { type: 'string', description: 'Purchasing group', optional: true },
Supplier: { type: 'string', description: 'Supplier key', optional: true },
NetAmount: { type: 'string', description: 'Net amount', optional: true },
DocumentCurrency: {
type: 'string',
description: 'Document currency',
optional: true,
},
LastChangeDateTime: {
type: 'string',
description: 'Last change timestamp',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,159 @@
import type { SapProxyResponse, UpdatePurchaseRequisitionParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updatePurchaseRequisitionTool: ToolConfig<
UpdatePurchaseRequisitionParams,
SapProxyResponse
> = {
id: 'sap_s4hana_update_purchase_requisition',
name: 'SAP S/4HANA Update Purchase Requisition',
description:
'Update fields on an A_PurchaseRequisitionHeader entity in SAP S/4HANA Cloud (API_PURCHASEREQ_PROCESS_SRV; deprecated since S/4HANA 2402, successor is API_PURCHASEREQUISITION_2 OData v4). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. Header-only — deep updates across navigations are not supported (SAP KBA 2833338); use the A_PurchaseReqnItem entity directly to modify items. If-Match defaults to a wildcard - for safe concurrent updates pass the ETag from a prior GET to avoid lost updates.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
purchaseRequisition: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PurchaseRequisition key to update (string, up to 10 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_PurchaseRequisitionHeader fields to update (e.g., {"PurchaseRequisitionType":"NB"})',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_PURCHASEREQ_PROCESS_SRV',
path: `/A_PurchaseRequisitionHeader(${quoteOdataKey(params.purchaseRequisition)})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description:
'Null on 204 success, or OData v2 envelope with updated A_PurchaseRequisitionHeader at output.data.d',
properties: {
d: {
type: 'json',
description: 'Updated A_PurchaseRequisitionHeader entity (if returned)',
optional: true,
properties: {
PurchaseRequisition: {
type: 'string',
description: 'Purchase requisition number',
},
PurchaseRequisitionType: {
type: 'string',
description: 'PR document type',
optional: true,
},
PurReqnDescription: {
type: 'string',
description: 'Purchase requisition description',
optional: true,
},
SourceDetermination: {
type: 'string',
description: 'Source-of-supply determination flag',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,163 @@
import type { SapProxyResponse, UpdateSalesOrderParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updateSalesOrderTool: ToolConfig<UpdateSalesOrderParams, SapProxyResponse> = {
id: 'sap_s4hana_update_sales_order',
name: 'SAP S/4HANA Update Sales Order',
description:
'Update fields on an A_SalesOrder header in SAP S/4HANA Cloud (API_SALES_ORDER_SRV). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. Header-only — deep updates to to_Item / to_Partner / to_PricingElement navigations are not supported (see SAP KBA 2833338); use A_SalesOrderItem operations for line-level changes. If-Match defaults to a wildcard (unconditional) — for safe concurrent updates pass the ETag from a prior GET to avoid lost updates.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
salesOrder: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'SalesOrder key to update (string, up to 10 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_SalesOrder fields to update (e.g., {"PurchaseOrderByCustomer":"PO-12345","HeaderBillingBlockReason":"01"})',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_SALES_ORDER_SRV',
path: `/A_SalesOrder(${quoteOdataKey(params.salesOrder)})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description:
'Null on 204 success; otherwise OData v2 envelope with the updated entity at output.data.d',
optional: true,
properties: {
d: {
type: 'json',
description: 'Updated A_SalesOrder entity (when SAP returns one)',
optional: true,
properties: {
SalesOrder: {
type: 'string',
description: 'Sales order number',
optional: true,
},
SalesOrderType: {
type: 'string',
description: 'Sales document type',
optional: true,
},
PurchaseOrderByCustomer: {
type: 'string',
description: 'Customer purchase order reference',
optional: true,
},
OverallSDProcessStatus: {
type: 'string',
description: 'Overall sales document process status',
optional: true,
},
OverallTotalDeliveryStatus: {
type: 'string',
description: 'Overall total delivery status',
optional: true,
},
},
},
},
},
},
}
@@ -0,0 +1,173 @@
import type { SapProxyResponse, UpdateSupplierParams } from '@/tools/sap_s4hana/types'
import {
baseProxyBody,
parseJsonInput,
quoteOdataKey,
SAP_PROXY_URL,
transformSapProxyResponse,
} from '@/tools/sap_s4hana/utils'
import type { ToolConfig } from '@/tools/types'
export const updateSupplierTool: ToolConfig<UpdateSupplierParams, SapProxyResponse> = {
id: 'sap_s4hana_update_supplier',
name: 'SAP S/4HANA Update Supplier',
description:
'Update fields on an A_Supplier entity in SAP S/4HANA Cloud (API_BUSINESS_PARTNER). Uses HTTP MERGE (OData v2 partial update) — only the fields you provide are written; existing values are preserved. A_Supplier is limited to modifiable fields such as PostingIsBlocked, PurchasingIsBlocked, PaymentIsBlockedForSupplier, DeletionIndicator, and SupplierAccountGroup; company-code/purchasing-org segments must be updated via the `to_SupplierCompany` / `to_SupplierPurchasingOrg` deep-update endpoints. If-Match defaults to a wildcard - for safe concurrent updates pass the ETag from a prior GET to avoid lost updates.',
version: '1.0.0',
params: {
subdomain: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'BTP region (e.g. eu10, us10)',
},
clientId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client ID from the S/4HANA Communication Arrangement',
},
clientSecret: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth client secret from the S/4HANA Communication Arrangement',
},
deploymentType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Deployment type: cloud_public (default), cloud_private, or on_premise',
},
authType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication type: oauth_client_credentials (default) or basic',
},
baseUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Base URL of the S/4HANA host (Cloud Private / On-Premise)',
},
tokenUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'OAuth token URL (Cloud Private / On-Premise + OAuth)',
},
username: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Username for HTTP Basic auth',
},
password: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for HTTP Basic auth',
},
supplier: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Supplier key to update (string, up to 10 characters)',
},
body: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'JSON object with A_Supplier fields to update (e.g., {"PaymentIsBlockedForSupplier":true,"PostingIsBlocked":true})',
},
ifMatch: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'If-Match ETag for optimistic concurrency. Defaults to "*" (unconditional).',
},
},
request: {
url: SAP_PROXY_URL,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => {
const payload = parseJsonInput<Record<string, unknown>>(params.body, 'body')
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('body must be a JSON object with the fields to update')
}
return {
...baseProxyBody(params),
service: 'API_BUSINESS_PARTNER',
path: `/A_Supplier(${quoteOdataKey(params.supplier)})`,
method: 'MERGE',
query: { $format: 'json' },
body: payload,
ifMatch: params.ifMatch || '*',
}
},
},
transformResponse: transformSapProxyResponse,
outputs: {
status: { type: 'number', description: 'HTTP status code returned by SAP (204 on success)' },
data: {
type: 'json',
description:
'Null on 204 success, or OData v2 envelope with updated entity at output.data.d when SAP returns a representation',
properties: {
d: {
type: 'json',
description: 'A_Supplier entity (when SAP returns a representation)',
optional: true,
properties: {
Supplier: {
type: 'string',
description: 'Supplier key (up to 10 characters)',
optional: true,
},
SupplierName: { type: 'string', description: 'Supplier name', optional: true },
SupplierAccountGroup: {
type: 'string',
description: 'Supplier account group',
optional: true,
},
BusinessPartner: {
type: 'string',
description: 'Linked BusinessPartner key',
optional: true,
},
PaymentIsBlockedForSupplier: {
type: 'boolean',
description: 'Payment block flag',
optional: true,
},
PostingIsBlocked: {
type: 'boolean',
description: 'Posting block flag',
optional: true,
},
PurchasingIsBlocked: {
type: 'boolean',
description: 'Purchasing block flag',
optional: true,
},
DeletionIndicator: {
type: 'boolean',
description: 'Central deletion flag',
optional: true,
},
},
},
},
},
},
}
+90
View File
@@ -0,0 +1,90 @@
import type { SapBaseParams } from '@/tools/sap_s4hana/types'
export const SAP_PROXY_URL = '/api/tools/sap_s4hana/proxy'
export function baseProxyBody(params: SapBaseParams) {
const body: Record<string, unknown> = {}
if (params.deploymentType) body.deploymentType = params.deploymentType
if (params.authType) body.authType = params.authType
if (params.subdomain) body.subdomain = params.subdomain
if (params.region) body.region = params.region
if (params.baseUrl) body.baseUrl = params.baseUrl
if (params.tokenUrl) body.tokenUrl = params.tokenUrl
if (params.clientId) body.clientId = params.clientId
if (params.clientSecret) body.clientSecret = params.clientSecret
if (params.username) body.username = params.username
if (params.password) body.password = params.password
return body
}
export function buildOdataQuery(opts: {
filter?: string
top?: number
skip?: number
orderBy?: string
select?: string
expand?: string
}): Record<string, string | number> {
const query: Record<string, string | number> = { $format: 'json' }
if (opts.filter) query.$filter = opts.filter
if (typeof opts.top === 'number') query.$top = opts.top
if (typeof opts.skip === 'number') query.$skip = opts.skip
if (opts.orderBy) query.$orderby = opts.orderBy
if (opts.select) query.$select = opts.select
if (opts.expand) query.$expand = opts.expand
return query
}
export function buildEntityQuery(opts: {
select?: string
expand?: string
}): Record<string, string> {
const query: Record<string, string> = { $format: 'json' }
if (opts.select) query.$select = opts.select
if (opts.expand) query.$expand = opts.expand
return query
}
export function parseJsonInput<T = unknown>(input: unknown, fieldName: string): T | undefined {
if (input === undefined || input === null || input === '') {
return undefined
}
if (typeof input === 'object') return input as T
if (typeof input !== 'string') {
throw new Error(`Invalid ${fieldName}: expected JSON object or string`)
}
try {
return JSON.parse(input) as T
} catch {
throw new Error(`Invalid ${fieldName}: must be valid JSON`)
}
}
export function quoteOdataKey(value: string): string {
return `'${String(value).trim().replace(/'/g, "''")}'`
}
export interface SapProxyToolOutput {
status: number
data: unknown
}
export async function transformSapProxyResponse(
response: Response
): Promise<{ success: boolean; output: SapProxyToolOutput; error?: string }> {
const data = (await response.json().catch(() => ({}))) as {
success?: boolean
output?: SapProxyToolOutput
error?: string
status?: number
}
if (!response.ok || data.success === false) {
throw new Error(data.error || `SAP request failed: HTTP ${response.status}`)
}
return {
success: true,
output: data.output ?? { status: response.status, data: null },
}
}