cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Help Needed: Error Uploading Salary Journal Entries from Excel to SAP Public Cloud via SOAP API

Akshaya14
Explorer
0 Kudos
326

Hello Experts,

I am working on a project to upload salary journal entries from an Excel sheet to SAP S/4HANA Public Cloud using a SOAP API.

I have created a Fiori app that:

  1. Uploads and processes Excel files using the XLSX library.
  2. Generates a SOAP request XML from the processed data.
  3. Sends the SOAP request to a CAP service, which then forwards the request to the SOAP API via a Destination configured in SAP BTP.

Here are the key components of my implementation:

View.xml:

mvc:View
    controllerName="project1.controller.View1"
    xmlns:mvc="sap.ui.core.mvc"
    xmlns="sap.m"
    xmlns:unified="sap.ui.unified">
    <Page id="page" title="Excel Upload Example">
        <content>
            <VBox id="vbox" class="sapUiSmallMargin">
                <Label id="L1" text="Upload Excel File" />
                <Panel id ="p1">
                    <content>
                        <unified:FileUploader
                            id="excelUploader"
                            name="myFileUpload"
                            width="400px"
                            placeholder="Choose an Excel file"
                            change="onFileChange" />
                    </content>
                </Panel>
                <Button id="btn" text="Process and Export" press="onProcessAndExport" />
               </VBox>
        </content>
    </Page>
</mvc:View>

 --------------------------------------------------------------------------------------------------------------------------------------
controller.js:
sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/ui/model/json/JSONModel",
    "sap/m/MessageToast"
 
], function (Controller, JSONModel, MessageToast ) {
    "use strict";
    return Controller.extend("project1.controller.View1", {
        onInit: function () {
            // Initialize the model for the table
            var oModel = new JSONModel({ data: [] });
            this.getView().setModel(oModel, "excelData");

        },

        onFileChange: function (oEvent) {
            var oFile = oEvent.getParameter("files")[0];
            if (oFile && window.FileReader) {
                var reader = new FileReader();
                reader.onload = function (e) {
                    var data = new Uint8Array(e.target.result);
                    var binaryString = '';
                    for (var i = 0; i < data.byteLength; i++) {
                        binaryString += String.fromCharCode(data[i]);
                    }

                    // Check if XLSX library is loaded
                    if (typeof XLSX === "undefined") {
                        MessageToast.show("XLSX library not loaded.");
                        return;
                    }

                    // Read the workbook
                    try {
                        var workbook = XLSX.read(binaryString, { type: 'binary' });
                        var sheetName = workbook.SheetNames[0];
                        var jsonSheet = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]);

                        // Set the data model
                        var oModel = this.getView().getModel("excelData");
                        oModel.setProperty("/data", jsonSheet);

                        MessageToast.show("Excel uploaded successfully!");
                    } catch (error) {
                        MessageToast.show("Error reading Excel file: " + error.message);
                    }
                }.bind(this);

                // Read as ArrayBuffer
                reader.readAsArrayBuffer(oFile);
            } else {
                MessageToast.show("No file selected or FileReader not supported.");
            }
        },

        onProcessAndExport: function () {
            var oModel = this.getView().getModel("excelData");
            var data = oModel.getProperty("/data");

            MessageToast.show("Processing data...");

            // Generate SOAP XML
            var soapXml = this.createSoapRequest(data);

            // Send the SOAP request
            this.callSendSoapRequestToCAP(soapXml);
        },

       
     
        createSoapRequest: function (data) {
            const creationDateTime = new Date().toISOString();
            const creationDate = creationDateTime.split('T')[0]; // Get date in YYYY-MM-DD format
            let envelope = `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sfin="http://sap.com/xi/SAPSCORE/SFIN">
                <soapenv:Header/>
                <soapenv:Body>
                    <sfin:JournalEntryBulkCreateRequest>
                        <MessageHeader>
                            <ID>MSG_${creationDate}</ID>
                            <CreationDateTime>${creationDateTime}</CreationDateTime>
                        </MessageHeader>`;

            // Group data by Journal Entry (if needed)
            const journalEntries = {}; // Store entries grouped by Document Reference ID

            data.forEach(entry => {
                const docRefId = entry.DocumentReferenceID; // Use this to group items

                if (!journalEntries[docRefId]) {
                    journalEntries[docRefId] = [];
                }

                // Push each entry to the corresponding Journal Entry group
                journalEntries[docRefId].push(entry);
            });

            // Loop through each journal entry and create JournalEntryCreateRequest
            Object.keys(journalEntries).forEach((docRefId, index) => {
                const entries = journalEntries[docRefId];

                const formatDate = (dateValue) => {
                    // Check if date is in Excel serial format (e.g., 45598)
                    if (typeof dateValue === "number") {
                        const excelBaseDate = new Date(Date.UTC(1899, 11, 30));
                        const dateObj = new Date(excelBaseDate.getTime() + dateValue * 86400000);
                        return dateObj.toISOString().split('T')[0];
                    }

                    // If date is a string, parse it and format it as YYYY-MM-DD
                    const dateObj = new Date(dateValue);
                    const year = dateObj.getFullYear();
                    const month = String(dateObj.getMonth() + 1).padStart(2, '0');
                    const day = String(dateObj.getDate()).padStart(2, '0');

                    return `${year}-${month}-${day}`;
                };

                const documentDate = formatDate(entries[0].DocumentDate);
                const postingDate = formatDate(entries[0].PostingDate);

                envelope += `
                    <JournalEntryCreateRequest>
                        <MessageHeader>
                            <ID>SUB_MSG_${creationDate}${index + 1}</ID>
                            <CreationDateTime>${creationDateTime}</CreationDateTime>
                        </MessageHeader>
                        <JournalEntry>
                            <OriginalReferenceDocumentType>${entries[0].OriginalReferenceDocumentType}</OriginalReferenceDocumentType>
                            <OriginalReferenceDocument/>
                            <OriginalReferenceDocumentLogicalSystem/>
                            <BusinessTransactionType>${entries[0].BusinessTransactionType}</BusinessTransactionType>
                            <AccountingDocumentType>${entries[0].AccountingDocumentType}</AccountingDocumentType>
                            <DocumentReferenceID>${docRefId}</DocumentReferenceID>
                            <DocumentHeaderText>${entries[0].DocumentHeaderText}</DocumentHeaderText>
                            <CreatedByUser>CC0000000001</CreatedByUser>
                            <CompanyCode>${entries[0].CompanyCode}</CompanyCode>
                            <DocumentDate>${documentDate}</DocumentDate>
                            <PostingDate>${postingDate}</PostingDate>
                            <Reference1InDocumentHeader>12345678901234567890</Reference1InDocumentHeader>
                            <Reference2InDocumentHeader>1234567890</Reference2InDocumentHeader>`;

                // Add items for each entry related to this journal entry
                entries.forEach(item => {
                    envelope += `
                            <Item>
                                <ReferenceDocumentItem>${item.ReferenceDocumentItem}</ReferenceDocumentItem>
                                <GLAccount>${item.GLAccount}</GLAccount>
                                <AmountInTransactionCurrency currencyCode="INR">${item.AmountInTransactionCurrency}</AmountInTransactionCurrency>
                                <DebitCreditCode>${item.DebitCreditCode}</DebitCreditCode>
                                <DocumentItemText>${item.DocumentItemText}</DocumentItemText>
                                <AccountAssignment>
                                    <CostCenter>${item.CostCenter}</CostCenter>
                                </AccountAssignment>
                            </Item>`;
                });

                envelope += `
                        </JournalEntry>
                    </JournalEntryCreateRequest>`;
            });

            envelope += `
                    </sfin:JournalEntryBulkCreateRequest>
                </soapenv:Body>
            </soapenv:Envelope>`;

            return envelope;
        },

        callSendSoapRequestToCAP: function (soapXml) {
            //var oService = this.getView().getModel();  // Get the service model
       
            // Ensure that you're invoking the action through the correct service model
            //oService.create("/readExcelData", { soapXml: soapXml }, {
              //  success: function (response) {
               //   MessageToast.show("SOAP request sent successfully!");
               //   console.log("Response from CAP: ", response);
               // },
               // error: function (error) {
               //   MessageToast.show("Error sending SOAP request: " + error.message);
               //   console.error("Error: ", error);
               // }
              //});


              var sUrl = "/odata/v4/excel/readExcelData"; // Adjust this to your CAPM service URL

              $.ajax({
                  url: sUrl,
                  method: "POST",
                  contentType: "application/xml", // Set the content type to XML
                  dataType: "xml",
                  data: soapXml, // Send the XML data
               
                  success: function (response) {
                      sap.m.MessageToast.show("Data submitted successfully!" , response);
                  },
                  error: function (error) {
                      sap.m.MessageToast.show("Error submitting data.");
                      console.error(error);
                  }
              });
        }
       
    });
});


------------------------------------------------------------------------------
srv --> .js file :
const cds = require('@sap/cds');
const path = require('path'); // For handling file paths
const XLSX = require('xlsx'); // For reading Excel files
const { executeHttpRequest } = require('@sap-cloud-sdk/http-client');
const { retrieveJwt } = require('@sap-cloud-sdk/core');
const xmlParser = require('fast-xml-parser');
const xml2js = require('xml2js');

module.exports = cds.service.impl(async function (req) {
    // Define an action in the service to read Excel data
    this.on('readExcelData', async (req) => {
        const contentType = req.headers['content-type'];
        const soapXml= req.data.soapXml;
        //const jsonData = JSON.parse(req.data);  // Parse the string data into JSON object

        console.log("data:", soapXml);

            //const xmlData = req.data; // Raw XML data

            //console.log(xmlData);

        const { DestinationService } = require('@sap-cloud-sdk/core');
        const axios = require('axios');

        //const soapXml = req.data.soapXml;

        // Retrieve destination from SAP BTP
        const destinationService = new DestinationService();
        const destination = await destinationService.getDestination('Qorix_COCKPIT'); // Use your destination name here

        // Now use the destination to make the API call
        let config = {
            method: 'post',
            url: destination.url,  // This is the URL from your destination
            headers: {
                'Content-Type': 'application/xml',
                'Authorization': 'Basic ' + destination.credentials, // Ensure that the correct credentials are used
                //'Cookie': 'sap-usercontext=sap-client=100'
            },
            data: soapXml,
        };

        try {
            const response = await axios.request(config);
            console.log('Response:', response.data);
        } catch (error) {
            console.error('Error:', error);
        }
    }

   

);
});

------------------------------------------------

 

srv --> .cds file:

service ExcelService {
    action readExcelData(soapXml: String) returns String;
}
 

----------------------------------------------------------------------

Error :

Akshaya14_2-1731771429340.png

 

 

 

Accepted Solutions (0)

Answers (0)