There could be many scenarios where we may have to deal with documents attached to the pdf form (SAP Interactive form). I had a particular scenario where end user fills in form and along with this; he is required to attach scanned copies of documents (like marriage certificate). Similarly there could be multiple attachments. Application would need to process interactive form with its attachments. Now this not only involves determining list of all the attachments but also to read those. This was challenging and I ventured on the journey to explore attachment related features of interactive form.
Attaching docs to PDF form – Let’s first understand how documents can be attached to interactive form. In Adobe Reader 7.0, navigate to ‘Tools --> Commenting --> Attach a file as comment’ menu.
Now after you browse to the relevant document, File Attachment Property box pops up. Using this box, you can define whether the document should be attached as an attachment or paperclip etc. You can give author data also in this box.
After attachment, the file will appear in the Attachments tab of the file.
Application -
PDF with attached Document:
After uploading the form in backend, application would determine the list of documents attached to the form.
User can click on the document name, and respective document will be opened.
Later, it can be printed or saved locally.
Step by Step approach:Now lets understand the step by step approach.
Layout Design: Assuming you’ve logged in NWDS (NW Developer Studio) and created a view, please follow below steps –
Add FileUpload UI element in the layout of the view.
Add a table, which will show the list of attachments in the form.
Add a button, after clicking on it, PDF file would be read.
Context Design:
Bind values DocContent to FileUpload.Data, FileUpload.resource and DocName to
FileUpload.filename.
Bind the Table of the view to the Tablenode node of the context. Bind FileName,
Description and MimeType to respective columns.
Now, in the onAction property of the button in layout assign ShowAttachment method.
Add the following code in ShowAttachment method. In this method:
Logic:
a) Read the PDF in fileResource variable of type IWDResource.
b) Convert PDF into Binary file, and add it to the table P_Rawtab.
c) Pass the table to BAPI Zrfc_Get_Attachment_List, and execute the BAPI.
d) After successful execution of the BAPI, list of attachment is returned in
table L_Attachments.
e) Bind the table to Tablenode of the context.
*******************************************************************************************
Code:
*******************************************************************************************
IPrivateAttachment_ApplView.IAttachmentElement element = wdContext.currentAttachmentElement();
try {
IWDMessageManager msgManager = wdComponentAPI.getMessageManager();
IWDResource fileResource = wdContext.currentAttachmentElement().getDocContent();
if (fileResource == null) {
msgManager.reportException("Can't Read the Document",false);
} else {
String fileName;
String fileType = fileResource.getResourceType().getFileExtension().toUpperCase();
if ("PDF".equals(fileType)
//Just I have added some validation, you can remove this
|| "DOC".equals(fileType)
|| "RTF".equals(fileType)
|| "XLS".equals(fileType)) {
element.setDocName( element.getDocContent().getResourceName());
} else {
msgManager.reportWarning("Document type could not be uploaded");
}
fileName = wdContext.currentAttachmentElement().getDocName();
InputStream fileStream = fileResource.read(false);
Zrfc_Get_Attachment_List_Input attach_Input = new Zrfc_Get_Attachment_List_Input();
int fileSize = 0;
byte[] lineContents = new byte[255];
int numBytesRead = 0;
do {
numBytesRead = fileStream.read(lineContents);
if (numBytesRead > 0) {
fileSize += numBytesRead;
Zstru_Raw255 attach = new Zstru_Raw255();
attach.setRaw255(lineContents);
attach_Input.addP_Rawtab(attach);
Arrays.fill(lineContents, (byte) 0);
}
} while (numBytesRead > 0);
wdContext.nodeZrfc_Get_Attachment_List_Input().bind(attach_Input);
wdContext.currentZrfc_Get_Attachment_List_InputElement().modelObject()
.execute();
wdContext.nodeOutput_RFC().invalidate();
int size = wdContext.nodeL_Attachments_Out().size();
IPrivateAttachment_ApplView.ITableNodeElement tableele;
IPrivateAttachment_ApplView.ITableNodeNode node = wdContext.nodeTableNode();
for (int i = 0; i<size; i++) {
tableele = node.createTableNodeElement();
tableele.setFileName( wdContext.nodeL_Attachments_Out()
.getL_Attachments_OutElementAt(i).getFilename());
tableele.setDescription(wdContext.nodeL_Attachments_Out()
.getL_Attachments_OutElementAt(i).getDescription());
tableele.setMimeType(wdContext.nodeL_Attachments_Out()
.getL_Attachments_OutElementAt(i).getMimetype());
tableele.setData(wdContext.nodeL_Attachments_Out()
.getL_Attachments_OutElementAt(i).getData());
node.addElement(tableele);
}
msgManager.reportSuccess("Document uploaded sucessfully. ");
}
} catch (Exception ex) {
wdComponentAPI.getMessageManager()
.reportException("Error in Reading Document " +
ex.getMessage(),false);
}
=======================================================================
Create one more action OpenAttachment, for showing the attachment. Convert fielname column of the table to LinktoAction. Assign action OpenAttachment to the onAction property of the LinktoAction element.
Logic and Code for the method OpenAttachment is as followed:
Logic:
a) Read the selected row of the table using getTreeSelection method of the table.
b) According to the file extension, call createCachedResource method of WDResourceFactory.
c) WDWebResourceType parameter can have value, according to the file extension.
In this case I have taken PDF, DOC and UNKNOWN.
d) Using resource.getUrl(0) and IWDWindow selected attachment is displayed in a different window.
*******************************************************************************************
Code:
*******************************************************************************************
try {
IPrivateAttachment_ApplView.ITableNodeElement selnode =
(IPrivateAttachment_ApplView.ITableNodeElement)
wdContext.nodeTableNode().getTreeSelection();
int name_len = selnode.getFileName().length();
IWDResource resource;
String file_ext = selnode.getFileName()
.substring(name_len - 3, name_len);
if (file_ext.toUpperCase().equals("PDF")) {
resource = WDResourceFactory.createCachedResource(
selnode.getData(), selnode.getFileName(), WDWebResourceType.PDF);
}else if(file_ext.toUpperCase().equals("DOC")){
resource = WDResourceFactory.
createCachedResource
(selnode.getData),selnode.getFileName(), WDWebResourceType.DOC);
}else{
resource = WDResourceFactory.
createCachedResource
(selnode.getData(), selnode.getFileName(), WDWebResourceType.UNKNOWN);
}
IWDWindow window = wdComponentAPI.getWindowManager()
.createNonModalExternalWindow(resource.getUrl(0),
selnode.getFileName());
window.show();
} catch (Exception ex) {
wdComponentAPI.getMessageManager().reportException("Error in Opening File ",false);
}
======================================================
A custom BAPI is called for reading the attachment of the Interactive form.
This BAPI has following attributes:
Logic:
a) Convert Binary string into XString using FM SCMS_BINARY_TO_XSTRING.
b) Create an instance of PDFObject class.
c) Call the method set_task_getattachments( ) of PDFObject class for setting the task to get attachment.
d) After executing the class, use get_attachments( ) of PDFObject class for getting list of attachment.
*******************************************************************************************
Code:
*******************************************************************************************
Name: ZRFC_GET_ATTACHMENT_LIST
Import Parameters:
P_LENGTH TYPE I Size of Part File
Export Parameters:
L_ATTACHMENTS TYPE TFPATTACHMENTS Attachment List
Tables:
P_RAWTAB LIKE ZSTRU_RAW255 Structure of Raw255
Source Code:
*"----------------------------------------------------------------------*"
*"Local Interface:
*" IMPORTING*" VALUE(P_LENGTH) TYPE I OPTIONAL
*" EXPORTING*" VALUE(L_ATTACHMENTS) TYPE TFPATTACHMENTS
*" TABLES*" P_RAWTAB STRUCTURE ZSTRU_RAW255 OPTIONAL
*"----------------------------------------------------------------------
TYPE-POOLS slis.
DATA: l_len TYPE i,
p_content TYPE xstring,
c_ads type rfcdest value 'ADS'.
DATA: l_fp TYPE REF TO if_fp,
l_pdfobj TYPE REF TO if_fp_pdf_object,
l_pdf TYPE xstring,
l_fpex TYPE REF TO cx_fp_runtime,
l_layout TYPE slis_layout_alv.
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
EXPORTING
input_length = p_length
IMPORTING
buffer = P_content
TABLES
binary_tab = p_rawtab[]
EXCEPTIONS
failed = 1
OTHERS = 2.
IF sy-subrc IS NOT INITIAL.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* Get FP reference.
l_fp = cl_fp=>get_reference( ).
TRY.
* Create PDF Object.
l_pdfobj = l_fp->create_pdf_object( connection = c_ads ).
* Set document.
l_pdfobj->set_document( pdfdata = p_content ).
* Set task to get attachments.
l_pdfobj->set_task_getattachments( ).
* Execute, call ADS.
l_pdfobj->execute( ).
* Get result.
l_attachments = l_pdfobj->get_attachments( ).
CATCH cx_fp_runtime_internal
cx_fp_runtime_system
cx_fp_runtime_usage INTO l_fpex.
ENDTRY.