feat(sap): add SAP Concur integration block and SAP S/4HANA validation fixes (#4483)

* feat(sap): add SAP Concur integration block and SAP S/4HANA validation fixes

* added

* fix(sap_s4hana): preserve raw Set-Cookie array for CSRF cookie join

SecureFetchHeaders previously collapsed multi-value Set-Cookie headers
with ", ", forcing consumers to re-split via a fragile regex. Cookie
values containing "=" or "," (e.g., Base64 session tokens) could be
misparsed and produce malformed Cookie strings on CSRF-protected
mutations.

Add SecureFetchHeaders.getSetCookie() that returns the raw array, and
update the S/4HANA OData proxy's joinSetCookies to consume it directly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap-concur): rename misleading exchange-rate tool, drop unusable refresh_token grant, validate geolocation host

- Rename sap_concur_get_exchange_rate to sap_concur_upload_exchange_rates (POST bulk upload, not GET)
- Remove refresh_token from SapConcurGrantType / Zod enum / block dropdown / docs (no implementation)
- Validate Concur geolocation hostname against SAP_CONCUR_ALLOWED_DATACENTERS

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* finished

* docs

* fix(docs): escape braces in tool/trigger description prose for MDX

Tool and trigger descriptions can contain URL path placeholders like
{reportId} or JSON-shape hints like { Items, NextPage }. When rendered
as MDX prose (not table cells), these were emitted unescaped and MDX
parsed them as JSX expressions, failing prerender with
"ReferenceError: reportId is not defined".

Escape { and } in the operation-level description and trigger
description renderers, matching the existing escaping in table-cell
descriptions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap-concur): align with live API on travel-profile, itineraries, and context types

- list_travel_profiles_summary: rename Status query to Active with 1/0 values, tighten LastModifiedDate format hint
- list_itineraries / get_itinerary: use documented userid_type / userid_value / ItemsPerPage / Page query keys
- create_report_comment: contextType allows MANAGER (move to EXPENSE_READ_CONTEXT_TYPE_OPS)
- get_list_item: drop unused listId from block (tool only needs itemId)
- Tighten description copy on list_expenses/get_itemizations/associate_attendees/remove_all_attendees

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap-concur): correct Cash Advance v4.1 paths, add SCIM filter param

- Update Cash Advance create/get/issue tools from /cashadvance/v4/ to /cashadvance/v4.1/ to match the live API
- Add filter query param to list_users (SCIM v4.1 supports filtering by userName, employeeNumber, externalId)
- Regenerate docs MDX

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap-concur): drop SCIM list_users filter param (not supported on v4.1 GET)

SCIM Identity v4.1 GET /Users does not accept a filter query parameter — filtering
is only supported via POST /Users/.search (already exposed by sap_concur_search_users).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap-concur): final live-API alignment

Verified against live SAP Concur docs (concur/developer.concur.com preview branch):

- Revert Cash Advance paths to /cashadvance/v4/ (v4.1 endpoints do not exist; live spec is v4)
- Travel Profile v2 summary has no Active/Status query param — drop the filter from tool, types, and block
- Report Comments v4 contextType is TRAVELER or PROXY only (NOT MANAGER) — move create_report_comment + list_report_comments into the TRAVELER/PROXY context group
- Trip v1.1 query keys: userid_type / userid_value / ItemsPerPage / Page (snake/Pascal per docs) — already correct, kept

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs

* fix(sap-concur): restore Cash Advance v4.1 paths

Re-verified against live developer.concur.com docs at /api-reference/cash-advance/v4-1.cash-advance.html — only v4.1 endpoints are documented:
- POST /cashadvance/v4.1/cashadvances
- GET /cashadvance/v4.1/cashadvances/{cashAdvanceId}
- POST /cashadvance/v4.1/cashadvances/{cashAdvanceId}/issue

The /cashadvance/v4/ docs page returns 404. Reverts the prior local rollback in 9ef3a11d7.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Waleed
2026-05-06 19:32:27 -07:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 7953c56aca
commit a251e45400
131 changed files with 20997 additions and 456 deletions
+19
View File
@@ -4141,6 +4141,25 @@ export function SapS4HanaIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function SapConcurIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 43.1 43.1'>
<path
fill='#F0AB00'
d='M20.5,28.2c-3.6,0-6.6-3-6.6-6.6s2.9-6.6,6.6-6.6c1.8,0,3.5,0.7,4.6,1.9l3.4-3.4c-2.1-2.1-4.9-3.3-8.1-3.3 C14.1,10.2,9,15.3,9,21.6S14.1,33,20.4,33c3.1,0,6-1.3,8.1-3.3l-3.4-3.4C23.9,27.4,22.3,28.2,20.5,28.2'
/>
<path
fill='#F0AB00'
d='M30.1,18.7c-1.6,0-2.9,1.3-2.9,2.9s1.3,2.9,2.9,2.9c1.6,0,2.9-1.3,2.9-2.9C33,20,31.7,18.7,30.1,18.7'
/>
<path
fill='#F0AB00'
d='M0,43.1h43.1V0H0V43.1z M4.8,38.2V4.8h33.4v15.5v2.4v15.5C38.2,38.2,4.8,38.2,4.8,38.2z'
/>
</svg>
)
}
export function ServiceNowIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 71.1 63.6'>
+2
View File
@@ -155,6 +155,7 @@ import {
RootlyIcon,
S3Icon,
SalesforceIcon,
SapConcurIcon,
SapS4HanaIcon,
SESIcon,
SearchIcon,
@@ -372,6 +373,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
rootly: RootlyIcon,
s3: S3Icon,
salesforce: SalesforceIcon,
sap_concur: SapConcurIcon,
sap_s4hana: SapS4HanaIcon,
search: SearchIcon,
secrets_manager: SecretsManagerIcon,
@@ -151,6 +151,7 @@
"rootly",
"s3",
"salesforce",
"sap_concur",
"sap_s4hana",
"search",
"secrets_manager",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -278,5 +278,15 @@ Upload files to a SharePoint document library
| ↳ `createdDateTime` | string | When the file was created |
| ↳ `lastModifiedDateTime` | string | When the file was last modified |
| `fileCount` | number | Number of files uploaded |
| `skippedFiles` | array | Files that were skipped before upload |
| ↳ `name` | string | File name |
| ↳ `size` | number | File size in bytes |
| ↳ `limit` | number | Upload size limit in bytes |
| ↳ `reason` | string | Reason the file was skipped |
| `skippedCount` | number | Number of files skipped |
| `errors` | array | Per-file upload errors |
| ↳ `name` | string | File name |
| ↳ `error` | string | Error message |
| ↳ `status` | number | HTTP status from Microsoft Graph |