From 502e50cfac9f0be0033bc00579b2384b2ef7228d Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 27 Apr 2026 19:32:49 -0700 Subject: [PATCH 1/3] fix(sap_s4hana): require non-empty items in create_purchase_order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: SAP A_PurchaseOrder POST silently fails or returns opaque errors without to_PurchaseOrderItem entries. Block already required this body but the tool marked it optional and didn't validate items presence — mismatched contract with create_sales_order / create_purchase_requisition. Also clarifies the deliveryDocument placeholder to show both outbound and inbound number ranges. Co-Authored-By: Claude Opus 4.7 --- apps/sim/blocks/blocks/sap_s4hana.ts | 2 +- apps/sim/tools/sap_s4hana/create_purchase_order.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/sim/blocks/blocks/sap_s4hana.ts b/apps/sim/blocks/blocks/sap_s4hana.ts index ec0e878024..40e932376d 100644 --- a/apps/sim/blocks/blocks/sap_s4hana.ts +++ b/apps/sim/blocks/blocks/sap_s4hana.ts @@ -417,7 +417,7 @@ export const SapS4HanaBlock: BlockConfig = { id: 'deliveryDocument', title: 'DeliveryDocument', type: 'short-input', - placeholder: '80000000', + placeholder: 'e.g., 80000000 (outbound) or 180000000 (inbound)', condition: { field: 'operation', value: ['sap_s4hana_get_outbound_delivery', 'sap_s4hana_get_inbound_delivery'], diff --git a/apps/sim/tools/sap_s4hana/create_purchase_order.ts b/apps/sim/tools/sap_s4hana/create_purchase_order.ts index 04dcc8662d..68e5dfcd32 100644 --- a/apps/sim/tools/sap_s4hana/create_purchase_order.ts +++ b/apps/sim/tools/sap_s4hana/create_purchase_order.ts @@ -107,10 +107,10 @@ export const createPurchaseOrderTool: ToolConfig ({ 'Content-Type': 'application/json' }), body: (params) => { const extra = parseJsonInput>(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 = { ...extra, PurchaseOrderType: params.purchaseOrderType, From 50a4e5efb0ad7e59b03a4a5548c9594e65e78a2f Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 27 Apr 2026 20:03:35 -0700 Subject: [PATCH 2/3] feat(sap_s4hana): add get_material_document and fix supplier invoice key order Co-Authored-By: Claude Opus 4.7 --- .../docs/content/docs/en/tools/sap_s4hana.mdx | 32 ++++- apps/docs/content/docs/en/tools/slack.mdx | 133 ++++++++++++++++++ .../integrations/data/integrations.json | 24 +++- apps/sim/blocks/blocks/sap_s4hana.ts | 31 ++++ apps/sim/tools/registry.ts | 2 + .../tools/sap_s4hana/get_material_document.ts | 122 ++++++++++++++++ .../tools/sap_s4hana/get_supplier_invoice.ts | 2 +- apps/sim/tools/sap_s4hana/index.ts | 1 + apps/sim/tools/sap_s4hana/types.ts | 7 + 9 files changed, 350 insertions(+), 4 deletions(-) create mode 100644 apps/sim/tools/sap_s4hana/get_material_document.ts diff --git a/apps/docs/content/docs/en/tools/sap_s4hana.mdx b/apps/docs/content/docs/en/tools/sap_s4hana.mdx index 1647bf5f70..1ab3ee754b 100644 --- a/apps/docs/content/docs/en/tools/sap_s4hana.mdx +++ b/apps/docs/content/docs/en/tools/sap_s4hana.mdx @@ -844,6 +844,36 @@ List material document headers (goods movements) from SAP S/4HANA Cloud (API_MAT | `status` | number | HTTP status code returned by SAP | | `data` | json | Array of A_MaterialDocumentHeader entities | +### `sap_s4hana_get_material_document` + +Retrieve a single material document header by composite key (MaterialDocumentYear + MaterialDocument) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `subdomain` | string | Yes | SAP BTP subaccount subdomain \(technical name of your subaccount, not the S/4HANA host\) | +| `region` | string | Yes | BTP region \(e.g. eu10, us10\) | +| `clientId` | string | Yes | OAuth client ID from the S/4HANA Communication Arrangement | +| `clientSecret` | string | Yes | OAuth client secret from the S/4HANA Communication Arrangement | +| `deploymentType` | string | No | Deployment type: cloud_public \(default\), cloud_private, or on_premise | +| `authType` | string | No | Authentication type: oauth_client_credentials \(default\) or basic | +| `baseUrl` | string | No | Base URL of the S/4HANA host \(Cloud Private / On-Premise\) | +| `tokenUrl` | string | No | OAuth token URL \(Cloud Private / On-Premise + OAuth\) | +| `username` | string | No | Username for HTTP Basic auth | +| `password` | string | No | Password for HTTP Basic auth | +| `materialDocumentYear` | string | Yes | MaterialDocumentYear \(4-character year, e.g., "2024"\) | +| `materialDocument` | string | Yes | MaterialDocument key \(string, up to 10 characters\) | +| `select` | string | No | Comma-separated fields to return \($select\) | +| `expand` | string | No | Comma-separated navigation properties to expand \(e.g., "to_MaterialDocumentItem"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `status` | number | HTTP status code returned by SAP | +| `data` | json | A_MaterialDocumentHeader entity | + ### `sap_s4hana_list_purchase_requisitions` 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. @@ -1047,7 +1077,7 @@ Create a purchase order in SAP S/4HANA Cloud (API_PURCHASEORDER_PROCESS_SRV, A_P | `purchasingOrganization` | string | Yes | PurchasingOrganization \(4 chars\) | | `purchasingGroup` | string | Yes | PurchasingGroup \(3 chars\) | | `supplier` | string | Yes | Supplier business partner key \(up to 10 chars\) | -| `body` | json | No | Additional A_PurchaseOrder fields and to_PurchaseOrderItem deep-insert items merged into the create payload \(e.g., \{"to_PurchaseOrderItem":\[\{"PurchaseOrderItem":"10","Material":"TG11","OrderQuantity":"5","Plant":"1010","PurchaseOrderQuantityUnit":"PC","NetPriceAmount":"100.00","DocumentCurrency":"USD"\}\]\}\). | +| `body` | json | Yes | 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"\}\]\}. | #### Output diff --git a/apps/docs/content/docs/en/tools/slack.mdx b/apps/docs/content/docs/en/tools/slack.mdx index 0c0a000e9c..61884d2cc6 100644 --- a/apps/docs/content/docs/en/tools/slack.mdx +++ b/apps/docs/content/docs/en/tools/slack.mdx @@ -925,6 +925,139 @@ Create a canvas pinned to a Slack channel as its resource hub | --------- | ---- | ----------- | | `canvas_id` | string | ID of the created channel canvas | +### `slack_get_canvas` + +Get Slack canvas file metadata by canvas ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `authMethod` | string | No | Authentication method: oauth or bot_token | +| `botToken` | string | No | Bot token for Custom Bot | +| `canvasId` | string | Yes | Canvas file ID to retrieve \(e.g., F1234ABCD\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `canvas` | object | Canvas file information returned by Slack | +| ↳ `id` | string | Unique canvas file identifier | +| ↳ `created` | number | Unix timestamp when the canvas was created | +| ↳ `timestamp` | number | Unix timestamp associated with the canvas | +| ↳ `name` | string | Canvas file name | +| ↳ `title` | string | Canvas title | +| ↳ `mimetype` | string | MIME type of the canvas file | +| ↳ `filetype` | string | Slack file type for the canvas | +| ↳ `pretty_type` | string | Human-readable file type | +| ↳ `user` | string | User ID of the canvas creator | +| ↳ `editable` | boolean | Whether the canvas file is editable | +| ↳ `size` | number | Canvas file size in bytes | +| ↳ `mode` | string | File mode | +| ↳ `is_external` | boolean | Whether the canvas is externally hosted | +| ↳ `is_public` | boolean | Whether the canvas is public | +| ↳ `url_private` | string | Private URL for the canvas file | +| ↳ `url_private_download` | string | Private download URL for the canvas file | +| ↳ `permalink` | string | Permanent URL for the canvas | +| ↳ `channels` | array | Public channel IDs where the canvas appears | +| ↳ `groups` | array | Private channel IDs where the canvas appears | +| ↳ `ims` | array | Direct message IDs where the canvas appears | +| ↳ `canvas_readtime` | number | Approximate read time for canvas content | +| ↳ `is_channel_space` | boolean | Whether this canvas is linked to a channel | +| ↳ `linked_channel_id` | string | Channel ID linked to this canvas | +| ↳ `canvas_creator_id` | string | User ID of the canvas creator | + +### `slack_list_canvases` + +List Slack canvases available to the authenticated user or bot + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `authMethod` | string | No | Authentication method: oauth or bot_token | +| `botToken` | string | No | Bot token for Custom Bot | +| `channel` | string | No | Filter canvases appearing in a specific channel ID | +| `count` | number | No | Number of canvases to return per page | +| `page` | number | No | Page number to return | +| `user` | string | No | Filter canvases created by a single user ID | +| `tsFrom` | string | No | Filter canvases created after this Unix timestamp | +| `tsTo` | string | No | Filter canvases created before this Unix timestamp | +| `teamId` | string | No | Encoded team ID, required when using an org-level token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `canvases` | array | Canvas file objects returned by Slack | +| ↳ `id` | string | Unique canvas file identifier | +| ↳ `created` | number | Unix timestamp when the canvas was created | +| ↳ `timestamp` | number | Unix timestamp associated with the canvas | +| ↳ `name` | string | Canvas file name | +| ↳ `title` | string | Canvas title | +| ↳ `mimetype` | string | MIME type of the canvas file | +| ↳ `filetype` | string | Slack file type for the canvas | +| ↳ `pretty_type` | string | Human-readable file type | +| ↳ `user` | string | User ID of the canvas creator | +| ↳ `editable` | boolean | Whether the canvas file is editable | +| ↳ `size` | number | Canvas file size in bytes | +| ↳ `mode` | string | File mode | +| ↳ `is_external` | boolean | Whether the canvas is externally hosted | +| ↳ `is_public` | boolean | Whether the canvas is public | +| ↳ `url_private` | string | Private URL for the canvas file | +| ↳ `url_private_download` | string | Private download URL for the canvas file | +| ↳ `permalink` | string | Permanent URL for the canvas | +| ↳ `channels` | array | Public channel IDs where the canvas appears | +| ↳ `groups` | array | Private channel IDs where the canvas appears | +| ↳ `ims` | array | Direct message IDs where the canvas appears | +| ↳ `canvas_readtime` | number | Approximate read time for canvas content | +| ↳ `is_channel_space` | boolean | Whether this canvas is linked to a channel | +| ↳ `linked_channel_id` | string | Channel ID linked to this canvas | +| ↳ `canvas_creator_id` | string | User ID of the canvas creator | +| `paging` | object | Pagination information from Slack | +| ↳ `count` | number | Number of items requested per page | +| ↳ `total` | number | Total number of matching files | +| ↳ `page` | number | Current page number | +| ↳ `pages` | number | Total number of pages | + +### `slack_lookup_canvas_sections` + +Find Slack canvas section IDs matching criteria for later edits + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `authMethod` | string | No | Authentication method: oauth or bot_token | +| `botToken` | string | No | Bot token for Custom Bot | +| `canvasId` | string | Yes | Canvas ID to search \(e.g., F1234ABCD\) | +| `criteria` | json | Yes | Section lookup criteria, such as \{"section_types":\["h1"\],"contains_text":"Roadmap"\} | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `sections` | array | Canvas sections matching the lookup criteria | +| ↳ `id` | string | Canvas section identifier | + +### `slack_delete_canvas` + +Delete a Slack canvas by its canvas ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `authMethod` | string | No | Authentication method: oauth or bot_token | +| `botToken` | string | No | Bot token for Custom Bot | +| `canvasId` | string | Yes | Canvas ID to delete \(e.g., F1234ABCD\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `ok` | boolean | Whether Slack deleted the canvas successfully | + ### `slack_create_conversation` Create a new public or private channel in a Slack workspace. diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index c6bdf4c25c..d29f3eb659 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -11493,6 +11493,10 @@ "name": "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." }, + { + "name": "Get Material Document", + "description": "Retrieve a single material document header by composite key (MaterialDocumentYear + MaterialDocument) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader)." + }, { "name": "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." @@ -11538,7 +11542,7 @@ "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." } ], - "operationCount": 37, + "operationCount": 38, "triggers": [], "triggerCount": 0, "authType": "none", @@ -12150,6 +12154,22 @@ "name": "Create Channel Canvas", "description": "Create a canvas pinned to a Slack channel as its resource hub" }, + { + "name": "Get Canvas Info", + "description": "Get Slack canvas file metadata by canvas ID" + }, + { + "name": "List Canvases", + "description": "List Slack canvases available to the authenticated user or bot" + }, + { + "name": "Lookup Canvas Sections", + "description": "Find Slack canvas section IDs matching criteria for later edits" + }, + { + "name": "Delete Canvas", + "description": "Delete a Slack canvas by its canvas ID" + }, { "name": "Create Conversation", "description": "Create a new public or private channel in a Slack workspace." @@ -12175,7 +12195,7 @@ "description": "Publish a static view to a user" } ], - "operationCount": 25, + "operationCount": 29, "triggers": [ { "id": "slack_webhook", diff --git a/apps/sim/blocks/blocks/sap_s4hana.ts b/apps/sim/blocks/blocks/sap_s4hana.ts index 40e932376d..fc5cd94c66 100644 --- a/apps/sim/blocks/blocks/sap_s4hana.ts +++ b/apps/sim/blocks/blocks/sap_s4hana.ts @@ -48,6 +48,7 @@ export const SapS4HanaBlock: BlockConfig = { { label: 'Update Product', id: 'sap_s4hana_update_product' }, { label: 'List Material Stock', id: 'sap_s4hana_list_material_stock' }, { label: 'List Material Documents', id: 'sap_s4hana_list_material_documents' }, + { label: 'Get Material Document', id: 'sap_s4hana_get_material_document' }, { label: 'List Purchase Requisitions', id: 'sap_s4hana_list_purchase_requisitions' }, { label: 'Get Purchase Requisition', id: 'sap_s4hana_get_purchase_requisition' }, { label: 'Create Purchase Requisition', id: 'sap_s4hana_create_purchase_requisition' }, @@ -189,6 +190,7 @@ export const SapS4HanaBlock: BlockConfig = { 'sap_s4hana_get_product', 'sap_s4hana_list_material_stock', 'sap_s4hana_list_material_documents', + 'sap_s4hana_get_material_document', 'sap_s4hana_list_purchase_requisitions', 'sap_s4hana_get_purchase_requisition', 'sap_s4hana_list_purchase_orders', @@ -225,6 +227,7 @@ export const SapS4HanaBlock: BlockConfig = { 'sap_s4hana_get_product', 'sap_s4hana_list_material_stock', 'sap_s4hana_list_material_documents', + 'sap_s4hana_get_material_document', 'sap_s4hana_list_purchase_requisitions', 'sap_s4hana_get_purchase_requisition', 'sap_s4hana_list_purchase_orders', @@ -556,6 +559,24 @@ export const SapS4HanaBlock: BlockConfig = { required: true, }, + // Material Document: get + { + id: 'materialDocumentYear', + title: 'MaterialDocumentYear', + type: 'short-input', + placeholder: '2024', + condition: { field: 'operation', value: 'sap_s4hana_get_material_document' }, + required: true, + }, + { + id: 'materialDocument', + title: 'MaterialDocument', + type: 'short-input', + placeholder: '4900000000', + condition: { field: 'operation', value: 'sap_s4hana_get_material_document' }, + required: true, + }, + // Supplier Invoice: get { id: 'supplierInvoice', @@ -844,6 +865,7 @@ export const SapS4HanaBlock: BlockConfig = { 'sap_s4hana_update_product', 'sap_s4hana_list_material_stock', 'sap_s4hana_list_material_documents', + 'sap_s4hana_get_material_document', 'sap_s4hana_list_purchase_requisitions', 'sap_s4hana_get_purchase_requisition', 'sap_s4hana_create_purchase_requisition', @@ -991,6 +1013,13 @@ export const SapS4HanaBlock: BlockConfig = { return { ...auth, ...listFields } case 'sap_s4hana_list_material_documents': return { ...auth, ...listFields } + case 'sap_s4hana_get_material_document': + return { + ...auth, + ...entityFields, + materialDocumentYear: params.materialDocumentYear, + materialDocument: params.materialDocument, + } case 'sap_s4hana_list_purchase_requisitions': return { ...auth, ...listFields } case 'sap_s4hana_get_purchase_requisition': @@ -1124,6 +1153,8 @@ export const SapS4HanaBlock: BlockConfig = { purchaseOrderBody: { type: 'json', description: 'Items and additional A_PurchaseOrder fields' }, supplierInvoice: { type: 'string', description: 'SupplierInvoice key' }, fiscalYear: { type: 'string', description: 'FiscalYear (4-digit year)' }, + materialDocumentYear: { type: 'string', description: 'MaterialDocumentYear (4-digit year)' }, + materialDocument: { type: 'string', description: 'MaterialDocument key' }, odataService: { type: 'string', description: 'OData service name' }, odataPath: { type: 'string', description: 'OData entity path' }, odataMethod: { type: 'string', description: 'HTTP method for OData call' }, diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 4a02631d70..af74992d5d 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -2258,6 +2258,7 @@ import { getBusinessPartnerTool as sapS4HanaGetBusinessPartnerTool, getCustomerTool as sapS4HanaGetCustomerTool, getInboundDeliveryTool as sapS4HanaGetInboundDeliveryTool, + getMaterialDocumentTool as sapS4HanaGetMaterialDocumentTool, getOutboundDeliveryTool as sapS4HanaGetOutboundDeliveryTool, getProductTool as sapS4HanaGetProductTool, getPurchaseOrderTool as sapS4HanaGetPurchaseOrderTool, @@ -5334,6 +5335,7 @@ export const tools: Record = { sap_s4hana_get_business_partner: sapS4HanaGetBusinessPartnerTool, sap_s4hana_get_customer: sapS4HanaGetCustomerTool, sap_s4hana_get_inbound_delivery: sapS4HanaGetInboundDeliveryTool, + sap_s4hana_get_material_document: sapS4HanaGetMaterialDocumentTool, sap_s4hana_get_outbound_delivery: sapS4HanaGetOutboundDeliveryTool, sap_s4hana_get_product: sapS4HanaGetProductTool, sap_s4hana_get_purchase_order: sapS4HanaGetPurchaseOrderTool, diff --git a/apps/sim/tools/sap_s4hana/get_material_document.ts b/apps/sim/tools/sap_s4hana/get_material_document.ts new file mode 100644 index 0000000000..e7ea7b3133 --- /dev/null +++ b/apps/sim/tools/sap_s4hana/get_material_document.ts @@ -0,0 +1,122 @@ +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 = { + id: 'sap_s4hana_get_material_document', + name: 'SAP S/4HANA Get Material Document', + description: + 'Retrieve a single material document header by composite key (MaterialDocumentYear + MaterialDocument) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader).', + version: '1.0.0', + params: { + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'SAP BTP subaccount subdomain (technical name of your subaccount, not the S/4HANA host)', + }, + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'BTP region (e.g. eu10, us10)', + }, + clientId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'OAuth client ID from the S/4HANA Communication Arrangement', + }, + clientSecret: { + type: 'string', + required: true, + 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: 'A_MaterialDocumentHeader entity' }, + }, +} diff --git a/apps/sim/tools/sap_s4hana/get_supplier_invoice.ts b/apps/sim/tools/sap_s4hana/get_supplier_invoice.ts index 9e5c3ac953..b27bb533e5 100644 --- a/apps/sim/tools/sap_s4hana/get_supplier_invoice.ts +++ b/apps/sim/tools/sap_s4hana/get_supplier_invoice.ts @@ -108,7 +108,7 @@ export const getSupplierInvoiceTool: ToolConfig ({ ...baseProxyBody(params), service: 'API_SUPPLIERINVOICE_PROCESS_SRV', - path: `/A_SupplierInvoice(SupplierInvoice=${quoteOdataKey(params.supplierInvoice)},FiscalYear=${quoteOdataKey(params.fiscalYear)})`, + path: `/A_SupplierInvoice(FiscalYear=${quoteOdataKey(params.fiscalYear)},SupplierInvoice=${quoteOdataKey(params.supplierInvoice)})`, method: 'GET', query: buildEntityQuery(params), }), diff --git a/apps/sim/tools/sap_s4hana/index.ts b/apps/sim/tools/sap_s4hana/index.ts index 0115fdfe7c..fb6a4a9d7b 100644 --- a/apps/sim/tools/sap_s4hana/index.ts +++ b/apps/sim/tools/sap_s4hana/index.ts @@ -7,6 +7,7 @@ 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' diff --git a/apps/sim/tools/sap_s4hana/types.ts b/apps/sim/tools/sap_s4hana/types.ts index c8103a212e..9c1db8db3d 100644 --- a/apps/sim/tools/sap_s4hana/types.ts +++ b/apps/sim/tools/sap_s4hana/types.ts @@ -228,6 +228,13 @@ export interface GetInboundDeliveryParams extends SapBaseParams { expand?: string } +export interface GetMaterialDocumentParams extends SapBaseParams { + materialDocumentYear: string + materialDocument: string + select?: string + expand?: string +} + export interface ListMaterialDocumentsParams extends SapBaseParams { filter?: string top?: number From 5be41b7b7e3f2516f8241ca9e2f9b7c21da2a4f7 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 27 Apr 2026 23:28:17 -0700 Subject: [PATCH 3/3] fix(sap_s4hana): align material doc key order in description and require purchase order body type --- apps/docs/content/docs/en/tools/sap_s4hana.mdx | 2 +- apps/sim/app/(landing)/integrations/data/integrations.json | 2 +- apps/sim/tools/sap_s4hana/get_material_document.ts | 2 +- apps/sim/tools/sap_s4hana/types.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/docs/en/tools/sap_s4hana.mdx b/apps/docs/content/docs/en/tools/sap_s4hana.mdx index 1ab3ee754b..57fde4ba95 100644 --- a/apps/docs/content/docs/en/tools/sap_s4hana.mdx +++ b/apps/docs/content/docs/en/tools/sap_s4hana.mdx @@ -846,7 +846,7 @@ List material document headers (goods movements) from SAP S/4HANA Cloud (API_MAT ### `sap_s4hana_get_material_document` -Retrieve a single material document header by composite key (MaterialDocumentYear + MaterialDocument) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader). +Retrieve a single material document header by composite key (MaterialDocument + MaterialDocumentYear) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader). #### Input diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index d29f3eb659..1f8c92d35f 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -11495,7 +11495,7 @@ }, { "name": "Get Material Document", - "description": "Retrieve a single material document header by composite key (MaterialDocumentYear + MaterialDocument) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader)." + "description": "Retrieve a single material document header by composite key (MaterialDocument + MaterialDocumentYear) from SAP S/4HANA Cloud (API_MATERIAL_DOCUMENT_SRV, A_MaterialDocumentHeader)." }, { "name": "List Purchase Requisitions", diff --git a/apps/sim/tools/sap_s4hana/get_material_document.ts b/apps/sim/tools/sap_s4hana/get_material_document.ts index e7ea7b3133..d360abbf14 100644 --- a/apps/sim/tools/sap_s4hana/get_material_document.ts +++ b/apps/sim/tools/sap_s4hana/get_material_document.ts @@ -12,7 +12,7 @@ export const getMaterialDocumentTool: ToolConfig | string + body: Record | string } export interface ListSupplierInvoicesParams extends SapBaseParams {