
AWS S3 Bucket triggering Lambda function to SAP OData API call

SAP S/4 HANA 2021 FPS02 Fully Activate Appliance on SAP CAL

SAP S/4 HANA instances running on AWS Cloud
{
"SalesOrderType":"OR",
"SalesOrganization":"1010",
"DistributionChannel":"10",
"OrganizationDivision":"00",
"SalesGroup":"",
"SalesOffice":"",
"SalesDistrict":"",
"SoldToParty":"10100011",
"PurchaseOrderByCustomer":"File dropped into S3 Bucket",
"to_Item":[
{
"SalesOrderItem":"10",
"Material":"TG11",
"RequestedQuantity":"1"
},
{
"SalesOrderItem":"20",
"Material":"TG12",
"RequestedQuantity":"5"
}
]
}
SAP Sales order service – API_SALES_ORDER_SRV

S3 Bucket ltc-inbound

File uploaded to the S3 Bucket

AWS CloudWatch Lambda function execution log

Lambda function detailed logs on AWS CloudWatch

Sales Order Response saved to AWS S3 Bucket
{
"d":
{
"__metadata":
{
"id": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')",
"uri": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')",
"type": "API_SALES_ORDER_SRV.A_SalesOrderType",
"etag": "W/\"datetimeoffset'2022-10-24T06%3A05%3A25.7050130Z'\""
},
"SalesOrder": "4969",
"SalesOrderType": "OR",
"SalesOrganization": "1010",
"DistributionChannel": "10",
"OrganizationDivision": "00",
"SalesGroup": "",
"SalesOffice": "",
"SalesDistrict": "",
"SoldToParty": "10100011",
"CreationDate": null,
"CreatedByUser": "",
"LastChangeDate": null,
"SenderBusinessSystemName": "",
"ExternalDocumentID": "",
"LastChangeDateTime": "/Date(1666591525705+0000)/",
"ExternalDocLastChangeDateTime": null,
"PurchaseOrderByCustomer": "File dropped into S3 J1",
"PurchaseOrderByShipToParty": "",
"CustomerPurchaseOrderType": "",
"CustomerPurchaseOrderDate": null,
"SalesOrderDate": "/Date(1666569600000)/",
"TotalNetAmount": "105.30",
"OverallDeliveryStatus": "",
"TotalBlockStatus": "",
"OverallOrdReltdBillgStatus": "",
"OverallSDDocReferenceStatus": "",
"TransactionCurrency": "EUR",
"SDDocumentReason": "",
"PricingDate": "/Date(1666569600000)/",
"PriceDetnExchangeRate": "1.00000",
"RequestedDeliveryDate": "/Date(1666569600000)/",
"ShippingCondition": "01",
"CompleteDeliveryIsDefined": false,
"ShippingType": "",
"HeaderBillingBlockReason": "",
"DeliveryBlockReason": "",
"DeliveryDateTypeRule": "",
"IncotermsClassification": "EXW",
"IncotermsTransferLocation": "Walldorf",
"IncotermsLocation1": "Walldorf",
"IncotermsLocation2": "",
"IncotermsVersion": "",
"CustomerPriceGroup": "",
"PriceListType": "",
"CustomerPaymentTerms": "0001",
"PaymentMethod": "",
"FixedValueDate": null,
"AssignmentReference": "",
"ReferenceSDDocument": "",
"ReferenceSDDocumentCategory": "",
"AccountingDocExternalReference": "",
"CustomerAccountAssignmentGroup": "01",
"AccountingExchangeRate": "0.00000",
"CustomerGroup": "01",
"AdditionalCustomerGroup1": "",
"AdditionalCustomerGroup2": "",
"AdditionalCustomerGroup3": "",
"AdditionalCustomerGroup4": "",
"AdditionalCustomerGroup5": "",
"SlsDocIsRlvtForProofOfDeliv": false,
"CustomerTaxClassification1": "",
"CustomerTaxClassification2": "",
"CustomerTaxClassification3": "",
"CustomerTaxClassification4": "",
"CustomerTaxClassification5": "",
"CustomerTaxClassification6": "",
"CustomerTaxClassification7": "",
"CustomerTaxClassification8": "",
"CustomerTaxClassification9": "",
"TaxDepartureCountry": "",
"VATRegistrationCountry": "",
"SalesOrderApprovalReason": "",
"SalesDocApprovalStatus": "",
"OverallSDProcessStatus": "",
"TotalCreditCheckStatus": "",
"OverallTotalDeliveryStatus": "",
"OverallSDDocumentRejectionSts": "",
"BillingDocumentDate": "/Date(1666569600000)/",
"ContractAccount": "",
"AdditionalValueDays": "0",
"CustomerPurchaseOrderSuplmnt": "",
"ServicesRenderedDate": null,
"to_Item":
{
"results":
[]
},
"to_Partner":
{
"__deferred":
{
"uri": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')/to_Partner"
}
},
"to_PaymentPlanItemDetails":
{
"__deferred":
{
"uri": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')/to_PaymentPlanItemDetails"
}
},
"to_PricingElement":
{
"__deferred":
{
"uri": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')/to_PricingElement"
}
},
"to_RelatedObject":
{
"__deferred":
{
"uri": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')/to_RelatedObject"
}
},
"to_Text":
{
"__deferred":
{
"uri": "https://**.**.***.*:*****/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder('4969')/to_Text"
}
}
}
}Sales Order response JSON file

Table entries in SAP table VBAK – sales order header table

Sales order transaction VA03

SAP Transaction VA03 – Sales order display

AWS Lambda Dashboard

Use the Blueprint to Get S3 Object

Blueprint Get S3 Object

processOrder Lambda function configuration

S3 trigger

Additional configuration for the lambda function

Generated Lambda Node.js code
// Author: Roland & Jay
// Note: This code requires the request and lodash npm modules
// Description: This code uses the AWS S3 events and objects and calls the SAP S/4 HANA sales order
// OData API service
console.log('Loading function')
const aws = require('aws-sdk')
const request = require('request')
const {get} = require('lodash')
const s3 = new aws.S3({ apiVersion: '2006-03-01' })
exports.handler = async (event, context) => {
//console.log('Received event:', JSON.stringify(event, null, 2))
// Get the object from the event and show its content type
const bucket = event.Records[0].s3.bucket.name
const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '))
const params = {
Bucket: bucket,
Key: key,
}
try {
const obj = await s3.getObject(params).promise()
const { ContentType, Body } = obj
const body = JSON.parse(Body.toString())
await processOrder(body)
return ContentType
} catch (err) {
console.log(err)
const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`
console.log(message)
throw new Error(message)
}
}
const hostname = '**.**.***.*'
const port = *****
const interface = 'sap/opu/odata/sap/API_SALES_ORDER_SRV'
const auth = {
user: '*********',
pass: '**********',
}
const bucket = 'ltc-outbound'
const buildCallParameters = (url, request, method = 'GET', extraHeaders = {}, jar = request.jar(), token = 'fetch', body) => {
console.log('build', method)
const params = {
url,
jar,
method,
rejectUnauthorized: false,
requestCert: true,
agent: false,
auth,
headers: {
'x-csrf-token': token,
...extraHeaders,
},
}
return !body ? params : { ...params, body, json: true }
}
const httpCall = async (url, request, method = 'GET', extraHeaders = {}, jar, token, body) => {
return new Promise((resolve, reject) => {
const params = buildCallParameters(url, request, method, extraHeaders, jar, token, body)
request(params,
(error, response) => {
if (error) {
return reject(error)
}
return resolve(response)
})
})
}
const postDataToSAP = async function (json, metaDataUrl, postUrl) {
const jar = request.jar()
const tokenResp = await httpCall(metaDataUrl, request, 'GET', {}, jar)
const token = tokenResp.headers['x-csrf-token']
console.log('token: ', token)
const postResp = await httpCall(
postUrl,
request,
'POST',
{ 'Content-Type': 'application/json' },
jar,
token,
json,
)
return postResp
}
const processOrder = async (order) => {
console.log('starting')
try {
const { body } = await postDataToSAP(
order,
`https://${hostname}:${port}/${interface}/$metadata`,
`https://${hostname}:${port}/${interface}/A_SalesOrder`,
)
console.log('success: ', body)
const orderNum = get(body, 'd.SalesOrder', 'error')
console.log(`writing sales order ${orderNum} to S3 bucket ${bucket}`)
await putObjectToS3(bucket, `${orderNum}.json`, JSON.stringify(body))
} catch (error) {
console.log('error:', error, ' error')
}
}
const putObjectToS3 = (bucket, key, data) => {
const params = {
Bucket: bucket,
Key: key,
Body: data
}
return new Promise((resolve, reject) => {
s3.putObject(params, (err, data) => {
if (err) {
return reject(err)
}
resolve(data)
})
})
}npm install request
npm install lodash
Upload the node_modules zip file with request and lodash npm modules

processOrderRole

Attach policies

Policy allow-sap-lambda-write-to-outbound

Policy allow-sap-lambda-write-to-outbound-policy
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 27 | |
| 24 | |
| 20 | |
| 19 | |
| 13 | |
| 13 | |
| 12 | |
| 12 | |
| 12 | |
| 11 |