4 weeks ago
Hello everyone,
I would like to consume an external S/4 backend service (odata) in my SAP CAP application. I have created the corresponding CDS schema and the calls also get through to the backend.
So far so good.
However, in addition to the normal parameters that are available in my CDS schema, there are also mandatory query parameters that I have to specify.
Hence the question: How can I add corresponding query parameters to my request?
I have already tried several possibilities and have actually found a workaround. However, I only see this option as a workaround and not as a permanent solution.
Basically, I build the URI for the call myself and execute the call via ext.send.
// connect to remote service
const ext = await cds.connect.to("ccp");
this.on("READ", "CustomerOpenItemSet", async (req) => {
//*********************************** */
//*********************************** */
//*********************************** */
//build url with query parameters
//*********************************** */
//*********************************** */
//*********************************** */
// Define the base URL path for the entity
let urlWithParams = "/CustomerOpenItemSet?BackendUser=00010000000003&Scenario=D";
// Manual addition of query parameters
if (req._query) {
// Extract the OData parameters from req.query and assemble them
const queryParams = [];
// Add further parameters such as $orderby, $select
if (req._query.$select) {
queryParams.push(`$select=${req._query.$select}`);
}
// for this command I get an error during the call
// if (req._query.$count) {
// queryParams.push(`$count=${req._query.$count}`);
// }
if (req._query.$skip) {
queryParams.push(`$skip=${req._query.$skip}`);
}
if (req._query.$top) {
queryParams.push(`$top=${req._query.$top}`);
}
if (req._query.$filter) {
queryParams.push(`$filter=${req._query.$filter}`);
}
if (req._query.$orderby) {
queryParams.push(`$orderby=${req._query.$orderby}`);
}
// Combine the query parameters in the URL
if (queryParams.length > 0) {
urlWithParams += `&${queryParams.join("&")}`;
}
}
console.log(urlWithParams);
try {
// Send the GET request with the dynamic parameters
const result = await ext.send({
method: "GET",
path: urlWithParams,
});
//I need this so that the result is displayed in the frontend
result.$count = result.length;
return result;
} catch (error) {
console.error("Error when retrieving the data:", error);
req.error({
code: "EXTERNAL_SERVICE_ERROR",
message: `Error when retrieving the data: ${error.message}`,
});
}
});
Below are a few two other attempts, none of which led to the desired result.
this.on("READ", "CustomerOpenItemSet_try1", async (req) => {
//*********************************** */
//*********************************** */
//*********************************** */
//add BackendUser as query-parameter
//*********************************** */
//*********************************** */
//*********************************** */
req._query.BackendUser = "00010000000003";
const result1 = await ext.run(req.query);
//OR
req.query.BackendUser = "00010000000003";
const result2 = await ext.run(req.query);
return result1;
//*********************************** */
//--> BackendUser does not arrive in the backend as a query parameter
//*********************************** */
});
this.on("READ", "CustomerOpenItemSet_try2", async (req) => {
//*********************************** */
//*********************************** */
//*********************************** */
//send-Request with query + headers
//*********************************** */
//*********************************** */
//*********************************** */
const result = await ext.send({
query: req.query,
headers: { BackendUser: "00010000000003" },
});
console.log(result);
return result;
//*********************************** */
//--> BackendUser does not arrive in the backend as a query parameter
//*********************************** */
});
Do the CAP experts have any good ideas for my problem? 🙂 @gregorw @qmacro etc.
I suppose these parameters are fixed for a connection. If so, you can add the following additional properties to the destination.
URL.queries.BackendUser=00010000000003
URL.queries.Scenario=D
The parameters will get added to the URL as query parameters.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Gregor,
unfortunately BackendUser and Scenario are not part of the OData metadata.
Although there are the properties BPCustomerNumber and CompanyCode (BackendUser is made up of CompanyCode + BPCustomerNumber), the service requires the BackendUser and Scenario to be specified via query parameters.
Below is the metadata of the CustomerOpenItem entity from which I want to determine the data. There ist no BackendUser and Scenario.
<EntityType Name="CustomerOpenItem" sap:content-version="1">
<Key>
<PropertyRef Name="AccountingDocument"/>
<PropertyRef Name="FiscalYear"/>
<PropertyRef Name="CompanyCode"/>
<PropertyRef Name="BPCustomerNumber"/>
<PropertyRef Name="AccountingDocumentItem"/>
</Key>
<Property Name="AccountingDocument" Type="Edm.String" Nullable="false" MaxLength="10" sap:unicode="false" sap:label="Belegnummer"/>
<Property Name="BillingDocument" Type="Edm.String" MaxLength="10" sap:unicode="false" sap:label="Vertriebsbeleg"/>
<Property Name="ReferenceDocumentNumber" Type="Edm.String" MaxLength="10" sap:unicode="false" sap:label="Belegnummer"/>
<Property Name="FiscalYear" Type="Edm.String" Nullable="false" MaxLength="4" sap:unicode="false" sap:label="Geschäftsjahr"/>
<Property Name="CompanyCode" Type="Edm.String" Nullable="false" MaxLength="4" sap:unicode="false" sap:label="Buchungskreis"/>
<Property Name="BPCustomerNumber" Type="Edm.String" Nullable="false" MaxLength="10" sap:unicode="false" sap:label="Debitor"/>
<Property Name="AccountingDocumentItem" Type="Edm.String" Nullable="false" MaxLength="3" sap:unicode="false" sap:label="Position"/>
<Property Name="NetDueDate" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Datum"/>
<Property Name="PostingDate" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Datum"/>
<Property Name="TransactionCurrency" Type="Edm.String" MaxLength="5" sap:unicode="false" sap:label="Währung" sap:semantics="currency-code"/>
<Property Name="AmountInTransactionCurrency" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="OpenAmountInTransCrcy" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="DocumentDate" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Belegdatum"/>
<Property Name="NetPaymentAmount" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="PaymentAmountInDisplayCrcy" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="DisplayCurrency" Type="Edm.String" MaxLength="5" sap:unicode="false" sap:label="Währung" sap:semantics="currency-code"/>
<Property Name="TotalAmountInDisplayCrcy" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="OpenAmountInDisplayCrcy" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="CashDiscountAmountInDspCrcy" Type="Edm.Decimal" Precision="23" Scale="4" sap:unicode="false" sap:label="Währungsbetrag"/>
<Property Name="CashDiscountDueDate" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Datum"/>
<Property Name="PartnerFunctionIsPrintRelevant" Type="Edm.Boolean" sap:unicode="false" sap:label="Feld zum Ankreuzen"/>
<Property Name="FunctionIsXMLRelevant" Type="Edm.Boolean" sap:unicode="false" sap:label="Feld zum Ankreuzen"/>
<Property Name="SpecialGLCode" Type="Edm.String" MaxLength="1" sap:unicode="false" sap:label="Sonderhauptb.Kz"/>
<Property Name="PostingKey" Type="Edm.String" MaxLength="2" sap:unicode="false" sap:label="Buchungsschl."/>
<Property Name="PostingKeyName" Type="Edm.String" MaxLength="20" sap:unicode="false" sap:label="Bedeutung"/>
<Property Name="DocumentReferenceID" Type="Edm.String" MaxLength="16" sap:unicode="false" sap:label="Referenz"/>
<Property Name="DebitCreditCode" Type="Edm.String" MaxLength="1" sap:unicode="false" sap:label="Soll/Haben"/>
<Property Name="AccountingDocExternalReference" Type="Edm.String" MaxLength="40" sap:unicode="false" sap:label="RechnungNr."/>
<Property Name="AccountingDocumentItemRef" Type="Edm.String" MaxLength="6" sap:unicode="false" sap:label="Zeilennummer"/>
<Property Name="InvoiceProcessingStatus" Type="Edm.String" MaxLength="2" sap:unicode="false" sap:label="Status"/>
<Property Name="PartialPaymentIsEnabled" Type="Edm.Boolean" sap:unicode="false" sap:label="Keine Teilzahlung"/>
<Property Name="PaymentIsEnabled" Type="Edm.Boolean" sap:unicode="false" sap:label="Feld zum Ankreuzen"/>
<Property Name="PartialPaymentHistoryDesc" Type="Edm.String" MaxLength="8192" sap:unicode="false" sap:label="SLD Agent: Ersatz für Typ "String" in Releases vor 4.5"/>
<Property Name="PaymentCurrency" Type="Edm.String" MaxLength="5" sap:unicode="false" sap:label="Währung" sap:semantics="currency-code"/>
<Property Name="PaymentTerms" Type="Edm.String" MaxLength="4" sap:unicode="false" sap:label="Zahlungsbed"/>
<Property Name="OriginalCashDiscount1Days" Type="Edm.Decimal" Precision="3" Scale="0" sap:unicode="false" sap:label="Tage 1"/>
<Property Name="OriginalCashDiscount2Days" Type="Edm.Decimal" Precision="3" Scale="0" sap:unicode="false" sap:label="Tage 2"/>
<Property Name="BranchAccount" Type="Edm.String" MaxLength="10" sap:unicode="false" sap:label="Filiale"/>
<Property Name="AccountingDocumentHeaderText" Type="Edm.String" MaxLength="25" sap:unicode="false" sap:label="Belegkopftext"/>
<Property Name="DueCalculationBaseDate" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Basisdatum"/>
</EntityType>
The service is based on the CL_API_EBPPOPLACCTGDOC_DPC_EXT class and the implementation can be found in the CUSTOMEROPENITEM_GET_ENTITYSET method.
As an example, I have the following FIORI Elements interface. There I filter for BPCustomerNumber and CompanyCode.
I have adapted the redefinition of onRead.CustomerOpenItemSet for the example as follows, so that the call is sent to the backend without ‘manipulation’.
The backend user is to be read from the query parameters of the URL in the ls_cust_param structure shown in the screenshot below.
The structure ls_odata_param contains, as expected, all the odata parameters like SORT, SELECT_COL, FILTER, ... The filter contains the filtered criterias from the FIORI surface.
The structure is then transferred to the function module EBPP_BD_GET_CUSTOMER_ITEMS. There is a condition whether the fields are filled. If this is not the case, the function module is no longer executed.
From my point of view, there is therefore no chance of using the ‘normal’ filter functionality to select the data.
If I manually fill the structure ls_cust_param in the debugger, I get the desired result. The filters from the ODATA model are also correctly taken.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
80 | |
11 | |
10 | |
10 | |
10 | |
8 | |
8 | |
7 | |
5 | |
5 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.