Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 69 additions & 34 deletions docs/abap/fiori-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,58 +59,93 @@ call).
largeObject); the user picks the file and the rows import. The action is surfaced on the list
report / object page through a **metadata extension** (see below).

!!! note "Frontend requirement: SAPUI5 ≥ 1.135"
File upload as an action parameter is a Fiori Elements (OData V4) feature **added in
SAPUI5 1.135** (April 2025). Older UI5 versions render the `FileContent` parameter as a
plain field. Backend requirement: see the release matrix below.

**Option fields** (on both parameters): `IsCsv` force CSV (else magic‑byte auto‑detect) · `IsDraft`
create drafts · `ChunkSize` rows/LUW (0 = default 500) · `DecimalSeparator` `'.'`/`','` · `HeaderRow`
1‑based header row. See [Options & data types](options.md).

## Surfacing the action in Fiori Elements (metadata extension)

In a Fiori Elements app the import action becomes a **button in the table toolbar** (and the upload
parameter renders a file picker) via a CDS **metadata extension** (DDLX) on your projection view — no
custom UI code. Conceptually:
In a Fiori Elements app the import action becomes a **button in the table toolbar** via a CDS
**metadata extension** (DDLX) on your projection view — no custom UI code. This is the (verified,
runnable) annotation from the samples' demo BO:

```abap
@Metadata.layer: #CORE
annotate entity ZC_YourProjection with
@UI: {
headerInfo: { typeName: 'Demo Order', typeNamePlural: 'Demo Orders',
title: { type: #STANDARD, value: 'OrderId' } }
}
annotate view ZSSI_C_S_ORD with
{
@UI.lineItem: [ { position: 10 } ] // a column …
YourField;
// the #FOR_ACTION line items put the import buttons in the table toolbar
@UI: { lineItem: [ { position: 10, importance: #HIGH },
{ type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Spreadsheet (File Upload)' },
{ type: #FOR_ACTION, dataAction: 'importExcel', label: 'Import Spreadsheet (Base64)' } ],
identification: [ { position: 10 },
{ type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Spreadsheet (File Upload)' } ],
selectionField: [ { position: 10 } ] }
OrderId;

@UI: { lineItem: [ { position: 20 } ], identification: [ { position: 20 } ] }
Customer;
}

// the action on the entity's toolbar:
@UI: { lineItem: [ { type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Excel' } ],
identification: [ { type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Excel' } ] }
```

!!! info "A complete, runnable example is in the samples"
The [samples repo](https://github.com/spreadsheetimporter/abap-spreadsheetimporter-samples) wires the
demo BO end‑to‑end for Fiori Elements — projection view, behaviour projection, service definition,
OData V4 UI service binding, and the metadata extension that puts the import button on the list
report — so you can build a Fiori Elements app on top and upload Excel files. The exact objects +
DDLX are shown here once published.

## The 758 on‑prem Fiori upload caveat
The full stack around it: projection view (`@Metadata.allowExtensions: true`, provider contract
`transactional_query`) → behavior projection (`use action importExcel; use action importUpload;
use function getCreateTemplate;`) → service definition → OData V4 UI service binding.

On **S/4HANA 2023 on‑prem**, the base64 **API channel is the universal, fully‑wired path**. The Fiori
`importUpload` control still renders a working `Edm.Stream` upload, but the mime‑type filter and file
name are not auto‑bound in the dialog — a confirmed **gateway framework‑version gap, not a modelling
bug**. The importer auto‑detects the file type from magic bytes regardless, so the import works either
way.
!!! info "A complete, runnable example is in the samples"
The [samples repo](https://github.com/spreadsheetimporter/abap-spreadsheetimporter-samples) ships the
whole thing — the wired demo BO (`ZSSI_R_S_ORD` + one‑line handlers), the projection stack with the
DDLX above, the published OData V4 service, **and a runnable Fiori Elements app**
(`app/demo-orders`) on top of it, including a custom "API channel" action
(`webapp/ext/ImportSpreadsheet.js`: file picker → base64 → `importExcel`) that works on every
supported release.

## Which channel works where (verified)

| | S/4HANA 2023 on‑prem (758) | BTP ABAP / S/4HANA Cloud (newer gateway) |
|---|---|---|
| **Native `importUpload` dialog** (needs SAPUI5 ≥ 1.135) | dialog **renders** — file‑upload control + the shipped field labels — but **submit fails**: the gateway cannot deserialize an inline `Edm.Stream` action parameter (`Parser error … while parsing an XML stream`) | ✅ works zero‑code (gateway emits the `Core.*` terms and accepts the stream payload) |
| **Base64 `importExcel`** — via API or an FE **custom action** | ✅ **works end‑to‑end** — verified live: per‑row BO messages (e.g. *"key value already in use"*) surface in the FE result dialog | ✅ works |

So on 758 build the upload button as a small FE **custom action** that base64‑encodes the picked file
and calls `importExcel` (the sample's
[`ImportSpreadsheet.js`](https://github.com/spreadsheetimporter/abap-spreadsheetimporter-samples/blob/main/app/demo-orders/webapp/ext/ImportSpreadsheet.js)
is exactly that, ~60 lines). Keep `importUpload` modeled — it lights up with zero change once the
backend moves to a gateway that supports it.

## The 758 on‑prem gateway gap (detail)

On **S/4HANA 2023 on‑prem**, the base64 **API channel is the universal, fully‑wired path**. The native
Fiori upload is blocked by the gateway in two ways — both **framework‑version gaps, not modelling
bugs** (verified empirically against a live 758 system, from curl *and* from a real FE 1.136 app):

1. `$metadata` carries **none** of the `Core.MediaType` / `Core.ContentDisposition` /
`Core.AcceptableMediaTypes` terms Fiori Elements uses to wire the mime filter and file name
(the `@EndUserText.label`s *do* arrive — the dialog fields are nicely labeled).
2. The action `POST` itself is rejected: the 758 gateway cannot deserialize an inline stream value in
the JSON action payload, in any representation (with/without `@odata.mediaContentType`, base64 or
base64url, OData 4.0 or 4.01 headers).

??? note "Why (the gateway detail)"
`ZSSI_A_FILE` is modelled *verbatim* per SAP's documented "File Upload as an Action Parameter" recipe
(`@Semantics.largeObject.mimeType/.fileName/.contentDispositionPreference:#INLINE` on `abap.rawstring`,
`@UI.hidden` on mime/filename). The live `$metadata` on 758 **does** render `FileContent` as
`Edm.Stream`, **but** the RAP→OData V4 gateway does **not** translate `@Semantics.largeObject` into the
`Core.MediaType` / `Core.ContentDisposition` / `Core.IsMediaType` / `Core.AcceptableMediaTypes` terms
that Fiori Elements needs to wire the mime filter and file name. The 758 `$metadata` carries **zero** of
those `Core.*` terms on the action‑parameter ComplexType.

This translation is done by the gateway metadata generator on SAP BTP ABAP / S/4HANA Cloud (and newer
on‑prem gateway SPs); it is not expressible via DDLX, a raw `@Core.*` passthrough, or a SRVD
annotation — the only on‑prem path is a gateway SP/note upgrade. Because the modelling already matches
SAP's recipe byte‑for‑byte, the dialog **auto‑wires on Cloud / a newer on‑prem gateway with zero change**
to this component.
`@UI.hidden` on mime/filename, `acceptableMimeTypes`). The live `$metadata` on 758 **does** render
`FileContent` as `Edm.Stream` (which is why the 1.135+ dialog shows the upload control), **but** the
RAP→OData V4 gateway does **not** translate `@Semantics.largeObject` into the `Core.*` terms, and its
JSON deserializer predates inline stream values in action payloads.

Neither half is expressible via DDLX, a raw `@Core.*` passthrough, or a SRVD annotation — the only
on‑prem path is a gateway SP/note upgrade. Because the modelling already matches SAP's recipe
byte‑for‑byte, the dialog **auto‑wires on Cloud / a newer on‑prem gateway with zero change** to this
component.

??? note "C1 API release (only for cross‑software‑component consumption on Cloud)"
The "use of non‑released API" ATC finding only fires when a *restricted* (ABAP for Cloud Development)
Expand Down
1 change: 1 addition & 0 deletions docs/abap/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
| Drafts created as active rows | No draft adapter registered for the BO | Generate + register a draft adapter — the generic engine is active‑only |
| Big file slow / memory | XCO holds the workbook in memory; one huge commit | Lower `rowThreshold`, tune `chunk_size`; consider splitting the file |
| `COMMIT ENTITIES is not allowed with this status` dump | You called the engine from inside a RAP action/handler | The engine owns the commit — call it from your own job/controller (or set `defer_commit` so the framework commits at request end); the upload action must only *store* the file |
| Fiori `importUpload` dialog: `Parser error … while parsing an XML stream` on submit | S/4HANA 2023 (758) gateway can't deserialize an inline `Edm.Stream` action parameter | Use the base64 `importExcel` channel (e.g. an FE custom action) on 758; the native dialog works on BTP ABAP / S/4HANA Cloud — see [Fiori Elements & file upload](fiori-elements.md#which-channel-works-where-verified) |
| Upload "succeeds", row has empty fields | A typed `CREATE FROM` without `%control` | Use `CREATE FIELDS ( … ) WITH` (auto‑sets control); the shipped handler / `fill_line` already do |

## Behaviour worth knowing
Expand Down
Loading