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
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:
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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 },
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user