cancel
Showing results for 
Search instead for 
Did you mean: 

SAP MDK fetch attachments from backend through OData

dhanikawick41
Participant
0 Kudos

Hi Experts,

I am tying to implement an attachment functionality through MDK for an offline app. I have already added the option to create an attachment and send it to the backend using Action.Type.ODataService.CreateMedia action.

My requirement is to show the attached files and also to fetch any attachments for an order in SAP, and show it in the app.

Should I use DownloadMedia action for it? What is the difference between Media and Stream? How can I fetch multiple attachments (images) from the backend and save it in the offline store? What controls should I use to display it again in the app?

I could not find helpful documents for this. Any guidance is much appreciated.

Thanks.

Jitendra_Kansal
Product and Topic Expert
Product and Topic Expert
0 Kudos

dhanikawick41

Were you able to resolve your issue? If any of the below responses helped you, then please mark the helpful answer by accepting it OR post an answer so others might benefit from your findings.

Regards, Jitendra (SAP Community Moderator)

Accepted Solutions (1)

Accepted Solutions (1)

ashishjain14
Employee
Employee

Hi Dhanika,

Downloading a media from an offline store is a 2 step process:

Step 1. Downloading the media from backend to offline store

Step 2. Retrieving the media from offline store, storing in a file format in the device and then referencing the file to view it.

Step 1 can be achieved in 2 ways:

  1. Download all the media files during app initialisation, this can be done by setting the AutomaticallyRetrievesStreams field in OfflineOData Initialize to true. There are 2 drawbacks of this approach one all the media files would be downloaded during app initialisation which would eventually slow down the complete app initialization process, second it would consume lot of disk space.
  2. Second approach if to download the media files on demand for this you can use the OfflineOData Download and just download the entity required.

For Step2 you will have to use the DownloadMedia action as for offline we currently support only v2 and DownloadStream is a v4 feature.

Regarding opening the media OpenDocument action would be the way forward to which you can pass the path of the file from local storage of the device.

Here are some of the code snippets which may help you achieve the same:

1. DownloadOrOpenDocument.js - This rule can be called on-press of say an ObjectCell

let fs = require('tns-core-modules/file-system');
export default function DownloadOrOpenDocument(sectionedTableProxy) {
  const pageProxy = sectionedTableProxy.getPageProxy();
  const bindingObject = pageProxy.getActionBinding();
  const readLink = bindingObject["@odata.readLink"];
  const filename = bindingObject.ProductId+".jpg";
  const serviceName = "/MDKMedia/Services/MDKMedia.service";
  const entitySet = 'Products';
  // first we need to decide if the media exists locally or needs to be downloaded
  return sectionedTableProxy.isMediaLocal(serviceName, entitySet, readLink).then((mediaIsLocal) => {
    const tempDir = fs.knownFolders.temp();
    const attachmentPath = fs.path.join(tempDir.path, filename);
    const fileExists = fs.File.exists(attachmentPath);
    if (mediaIsLocal && fileExists) {
      // the media has been downloaded, we can open it -> the path needs to be provided in the action definition
      // or it should come from binding
      // persist the media data to local sandbox, so we can open it with the document viewer
      if (!bindingObject) {
        return pageProxy.executeAction("/MDKMedia/Actions/ODataDownloadFailure.action");
      }
      if (readLink) {
          pageProxy.setActionBinding({
            'FileName': attachmentPath
          });
          return pageProxy.executeAction("/MDKMedia/Actions/OpenRelatedDocument.action")
      }
    } else if (mediaIsLocal) {
      //  The media is on the offline store but the file hasn't been saved
      if (pageProxy.getClientData()[readLink]) {
        // we have the stream in client data, save and open
        const attachmentFile = fs.File.fromPath(attachmentPath);
        attachmentFile.writeSync(pageProxy.getClientData()[readLink], function (err) {
          attachmentFile.remove();
          return pageProxy.executeAction('/MDKMedia/Actions/ODataDownloadFailure.action');
        });
        pageProxy.setActionBinding({
          'FileName': attachmentPath
        });
        return pageProxy.executeAction('/MDKMedia/Actions/OpenRelatedDocument.action');
      } 
    } 
    else {
      if (sectionedTableProxy.downloadInProgressForReadLink(readLink)) {
        return Promise.resolve();
      } else {
        return sectionedTableProxy.executeAction("/MDKMedia/Actions/DownloadDocumentStreams.action").catch(error => {
        });
      }
    }
  });
}

2. DownloadDocumentStreams.action - This is required to get media on demand from backend store

{"DefiningRequests": [{"AutomaticallyRetrievesStreams": true,"Name": "{ProductId}","Query": "{@odata.readLink}"}],"OnSuccess": "/MDKMedia/Actions/DownloadImage.action","Service": "/MDKMedia/Services/MDKMedia.service","_Type": "Action.Type.OfflineOData.Download"}

3. DownloadImage.action - this will be called once the offline store has been populated with the required media

{"OnSuccess": "/MDKMedia/Rules/DocumentFileSave.js","Target": {"EntitySet": "Products","ReadLink": "{@odata.readLink}","Service": "/MDKMedia/Services/MDKMedia.service"},"_Type": "Action.Type.ODataService.DownloadMedia"}

4. DocumentFileSave.js - This rule will save the media in local device

let fs = require('tns-core-modules/file-system');
export default function DocumentFileSave(pageProxy) {
  console.log("In saving media");
  const binding = pageProxy.getActionBinding();
  let readLink = binding['@odata.readLink'];
  var filename = binding.ProductId+".jpg";
  if (readLink && filename) {
    var tempDir = fs.knownFolders.temp();
    var attachmentPath = fs.path.join(tempDir.path, filename);
    var attachmentFile = fs.File.fromPath(attachmentPath);
    attachmentFile.writeSync(pageProxy.getClientData()[readLink], err => {
      attachmentFile.remove();
      return pageProxy.executeAction('/MDKMedia/Actions/ODataDownloadFailure.action');
    });
    pageProxy.setActionBinding({
      'Path': attachmentPath,
    });
    return pageProxy.executeAction('/MDKMedia/Actions/SuccessBanner.action');
  }
}

5. OpenRelatedDocument.action - finally the action which will open the attachment

{
"Path": "{FileName}",
"_Type": "Action.Type.OpenDocument"
}

Regards,

Ashish

dhanikawick41
Participant
0 Kudos

Hi ashishjain14,

Thank you for the great explanation with code snippets. I will try out the way you have mentioned.

Thank you very much!

Answers (0)