
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 |
---|---|
11 | |
6 | |
6 | |
5 | |
4 | |
3 | |
3 | |
3 | |
2 | |
2 |