Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Jacky_Liu
Product and Topic Expert
Product and Topic Expert
In S/4 Hana Cloud side by side extension , we need to develope backend to create material document in S/4 Hana cloud . In this case we use nodejs .  If we use SAP Cloud SDK , it will improve our developement efficiency greatly . Today I want to demo how to create material document in S/4 Hana Cloud with SAP Cloud SDK in nodejs .

In api hub in the following linkage , we can check cloud sdk for material document .


SAP API Business Hub



 

Code snippy:


package.json
{
"name": "capdemo23-srv",
"engines": {
"node": "14.x"
},
"dependencies": {
"@sap-cloud-sdk/core": "latest",
"@sap/cloud-sdk-vdm-material-document-service": "latest",
"@sap-cloud-sdk/temporal-de-serializers": "latest",
"@sap/hana-client": "^2.12.22",
"@sap/xsenv": "latest",
"@sap/xssec": "latest",
"body-parser": "latest",
"cors": "latest",
"express": "latest",
"passport": "latest"
},
"scripts": {
"start": "node server.js"
}
}

server.js



const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const { temporalDeSerializersV2 } = require('@sap-cloud-sdk/temporal-de-serializers');

const xsenv = require('@sap/xsenv');
xsenv.loadEnv();
const services = xsenv.getServices({
uaa: { tag: 'xsuaa' }
});


const xssec = require('@sap/xssec');
const passport = require('passport');
passport.use('JWT', new xssec.JWTStrategy(services.uaa));
app.use(passport.initialize());
app.use(passport.authenticate('JWT', {
session: false
}));

app.use(bodyParser.json());
app.use(cors());

const { retrieveJwt } = require('@sap-cloud-sdk/core');
const { desc } = require('@sap-cloud-sdk/core');
const{ materialDocumentService } =require('@sap/cloud-sdk-vdm-material-document-service');
const { json } = require('body-parser');
const{materialDocumentHeaderApi,materialDocumentItemApi}=materialDocumentService(temporalDeSerializersV2);


function postMaterialDoc(req){
// console.log(req.body);
let docs = new Array();

req.body.to_MaterialDocumentItem.forEach(function(e){
let doc = materialDocumentItemApi.entityBuilder()
.material(e.Material).plant(e.Plant).storageLocation(e.StorageLocation)
.goodsMovementType(e.GoodsMovementType).purchaseOrder(e.PurchaseOrder)
.purchaseOrderItem(e.PurchaseOrderItem).goodsMovementRefDocType(e.GoodsMovementRefDocType)
.entryUnit(e.EntryUnit).quantityInEntryUnit(e.QuantityInEntryUnit).build();
docs.push(doc);
});
const materialDoc = materialDocumentHeaderApi.entityBuilder().postingDate(req.body.PostingDate).goodsMovementCode(req.body.GoodsMovementCode).toMaterialDocumentItem(docs).build();
console.log(materialDoc);
return materialDocumentHeaderApi.requestBuilder().create(materialDoc).execute({
destinationName: 'O5P' ,
jwt: retrieveJwt(req)
});
}

app.post('/srv/materialdoc',function(req,res){
postMaterialDoc(req).then( result => {
res.status(200).json(result);
}).catch(err=>{
res.status(500).json(err);
});

});



const port = process.env.PORT || 5001;
app.listen(port, function () {
console.info('Listening on http://localhost:' + port);
});

mta.yml
ID: capdemo23
_schema-version: "3.1"
version: 0.0.1

parameters:
enable-parallel-deployments: true

modules:

- name: capdemo23-srv
type: nodejs
path: srv
parameters:
disk-quota: 512M
memory: 256M
provides:
- name: srv_api
properties:
url: ${default-url}
requires:
- name: capdemo23-uaa
- name: capdemo23-dest

- name: capdemo23-app
type: html5
path: app
parameters:
disk-quota: 512M
memory: 256M
requires:
- name: capdemo23-uaa
- name: srv_api
group: destinations
properties:
name: srv
url: ~{url}
forwardAuthToken: true
resources:
- name: capdemo23-uaa
type: org.cloudfoundry.managed-service
parameters:
path: ./xs-security.json
service-plan: application
service: xsuaa
- name: capdemo23-dest
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-plan: lite
config:
init_data:
instance:
existing_destinations_policy: ignore
destinations:
- Name: capdemo23-s4hc-api
Description: S/4HANA Cloud
URL: https://sandbox.api.sap.com/s4hanacloud
Type: HTTP
ProxyType: Internet
Authentication: NoAuthentication
URL.headers.APIKey: <SetValueInCockpit>
URL.headers.Application-Interface-Key: <SetValueInCockpit>

xs-security.json
{
"xsappname": "capdemo23",
"tenant-mode": "dedicated",
"scopes": [
{
"name": "$XSAPPNAME.User",
"description": "User"
},
{
"name": "$XSAPPNAME.Admin",
"description": "Admin"
}
],
"role-templates": [
{
"name": "User",
"description": "User",
"scope-references": [
"$XSAPPNAME.User"
]
},
{
"name": "Admin",
"description": "Admin",
"scope-references": [
"$XSAPPNAME.Admin"
]
}
],
"role-collections": [
{
"name": "capdemo23_User",
"description": "capdemo23 User",
"role-template-references": [
"$XSAPPNAME.User"
]
},
{
"name": "capdemo23_Admin",
"description": "capdemo23 Admin",
"role-template-references": [
"$XSAPPNAME.Admin"
]
}
]
}

 

Build the project with :


mbt build

 

deploy the application to BTP cloud foundry with the following command, after you have login in BTP with cf login


cf deploy  the_generated_mta_file.mtar


Create communication arrangement in s/4 hana cloud:


 



Create  destination in BTP:




Test the deployed application with postman


get the deployed url and oauth information





The end .

 

Best Regards!

Jacky Liu