DATA(maximum) = REDUCE #( INIT max = VALUE myType( )
FOR line IN myTable
NEXT max = COND #( WHEN line-myColumn > max THEN line-myColumn
ELSE max ) ).
Tag: SAP
[ABAP] OData – GET_STREAM implementation to return a PDF
METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.
* This method get's called when a media file is queried with $value. A binary stream will be returned.
TRY.
DATA(file_id) = VALUE zfile_id( it_key_tab[ name = 'file_id' ]-value ).
CATCH cx_sy_itab_line_not_found.
RETURN. " leave here when no file_id provided
ENDTRY.
DATA(ls_file) = get_file( file_id ) " read your file you want to return (if it's not yet a binary stream, convert it)
DATA(ls_stream) = VALUE ty_s_media_resource( value = ls_file-value
mime_type = ls_file-mimetype ). " in my case it's 'application/pdf'
" necessary to display the filename instead of $value in the viewer title
TRY.
" create pdf object
DATA(lo_fp) = cl_fp=>get_reference( ).
DATA(lo_pdfobj) = lo_fp->create_pdf_object( connection = 'ADC' ).
lo_pdfobj->set_document( pdfdata = ls_stream-value ).
" set title
lo_pdfobj->set_metadata( VALUE #( title = ls_file-filename ) ).
lo_pdfobj->execute( ).
" get pdf with title
lo_pdfobj->get_document( IMPORTING pdfdata = ls_stream-value ).
CATCH cx_fp_runtime_internal
cx_fp_runtime_system
cx_fp_runtime_usage INTO DATA(lo_fpex).
ENDTRY.
copy_data_to_ref( EXPORTING is_data = ls_stream
CHANGING cr_data = er_stream ).
" necessary for the pdf to be opened inline instead of a download (also sets the filename when downloaded)
/iwbep/if_mgw_conv_srv_runtime~set_header( VALUE #( name = 'content-disposition'
value = |inline; filename={ ls_file-filename }| ) ).
ENDMETHOD
Quick way to open a PDFViewer in your UI5 App:
const pdfViewer = new PDFViewer()
pdfViewer.setSource("/sap/opu/odata/ZMY_SEVICE" + my_path + "/$value") // my_path could be something like this "/PdfSet('file_id')"
pdfViewer.setTitle("My PDFViewer Title") // title of the popup, not the viewer
pdfViewer.open()
[ABAP] Create DATA-URL from xstring
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
DATA lv_filetype TYPE char4.
DATA lv_content TYPE xstring.
" get your data, for example a jpg
" lv_filetype = 'jpg'
" lv_content = ....
DATA(mimetype) = /iwwrk/cl_mgw_workflow_rt_util=>get_mime_type_from_extension( lv_filetype ).
DATA(base64) = /iwwrk/cl_mgw_workflow_rt_util=>base64_encode( lv_content ).
DATA(lv_data_url) = |data:{ mimetype };base64,{ base64 }|.
[ABAP] OData – Filtering, Sorting, Paging
" Filter, Sort, Paging
/iwbep/cl_mgw_data_util=>filtering( EXPORTING it_select_options = it_filter_select_options
CHANGING ct_data = et_entityset ).
/iwbep/cl_mgw_data_util=>orderby( EXPORTING it_order = it_order
CHANGING ct_data = et_entityset ).
/iwbep/cl_mgw_data_util=>paging( EXPORTING is_paging = is_paging
CHANGING ct_data = et_entityset ).
[ABAP] Delete all rows from index
If you want to delete all lines from a certain index, e.g. 6, you can do the following:
DELETE lt_data FROM 6 TO lines( lt_data ).
As result, your table will only hold the first 5 rows.
[SAPUI5] Get data of an Item of a List or Table
All options have in common that you first try to get the binding context from the list/table element via the event. Having the right context, you can either use the getProperty()
function to get a specific property, or use the getObject()
function to get all data.
onClick: function (oEvent) {
// Option 1
oEvent.getParameters().item.getBindingContext().getProperty("ID")
// Option 2
oEvent.getParameters().item.getBindingContext().getObject().ID
// Option 3
oEvent.getParameter("item").getBindingContext().getObject().ID
// Option 4
oEvent.getSource().getBindingContext().getObject().ID
}
Note: When using a List, it’s oEvent.getParameters().listItem
instead of oEvent.getParameters().item
.
Or you could also use the sPath
property from the binding context and directly get the data from the model.
onClick: function (oEvent) {
// Option 5
const sPath = oEvent.getSource().getBindingContext().sPath
// 5a
this.getView().getModel().getProperty(sPath).ID
// 5b
this.getView().getModel().getProperty(sPath + "/ID")
}
[ABAP] OData – Get the “low” value from a filter range
DATA(lt_filter) = io_tech_request_context->get_filter( )->get_filter_select_options( ).
IF line_exists( it_filter[ property = 'MYKEY' ] ).
DATA(lv_input) = it_filter[ property = 'MYKEY' ]-select_options[ 1 ]-low.
" ...
ENDIF.
[CAP] Invoke custom handlers when querying local entity
const cds = require('@sap/cds');
module.exports = async srv => {
const { Objects } = srv.entities // entities from myService.cds
srv.on("myAction", async req => {
const query = SELECT.one.from(Objects).where({ id: req.data.myId })
const srv = await cds.connect.to('myService')
const data = await srv.run(query)
console.log(data)
return data
})
srv.on("READ", Objects, async req => {
console.log("Objects called")
// Select data from db or forward query to external system
// ...
// return data
})
}
[SuccessFactors] Create JavaScript Date-Object from DateTimeOffset
The SuccessFactors oData v2 API is returning timestamps in Unix Epoch format (unix-style milliseconds since 1/1/1970).
Many timestamp fields are of type Edm.Int64. When receiving the milliseconds as Integer, you can directly create a date-object of it using Date(1658237847)
.
But some timestamps are of type Edm.DateTimeOffset, i.e.: "createdDate": "/Date(1652252620000+0000)/"
.
When binding a timestamp property with an ODataModel
, the internal lib datajs will convert the /Date(...)/
value to a standard JS date-object.
But in my case I manually had to convert the timestamp and this is the shortest way I found to convert the epoch string into a JS date-object.
// SF epoch date string
const SFdateString = '/Date(1652252620000+0000)/'
// remove the '/' on both sides and create the date object
const oDate = eval('new ' + SFdateString .slice(1, -1))
console.log(typeof oDate )
console.log(oDate )
const oDateTimeFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({
pattern: "YYYY-MM-dd HH:mm"
})
return oDateTimeFormat.format(oDate)
[Workflow] You are not one of the possible agents of task ‘&1’
The Function Module SAP_WAPI_START_WORKFLOW uses RH_TASK_START_CHECK to check, if the calling user is allowed to start the Workflow.
In it RH_TASKS_TO_START is used to read the WF and Task IDs which the user is allowed to call. But it uses a buffer and if you just did some changes to the Workflow Classification, i.e. setting it to General Task,

it can be that this check will continue to fail as it is reading old data from the buffer.

You will receive an error message from Message Class WZ: You are not one of the possible agents of task ‘&1’

I had this problem sometimes when transporting objects to the next system, but until now I could not figure out when it happens and when not.
Luckily the solution is pretty simple, just call T-Code SWU_OBUF and do a buffer refresh/synchronization.
Rob Dielemans has explained the cause very well here.