How to execute Report given the results of a previously executed Report in ABAP - submit

My problem is the following:
I have one report called Y5000112.
My colleagues always execute it manually once with selection screen variant V1 and then execute it a second time with variant V2 adding the results of the first execution to the selection.
Those results in this case are PERNR.
My goal:
Automate this - execute that query twice with one click and automatically fill the PERNR selection of the second execution with the PERNR results of the first execution.
I found out how to trigger a report execution and after that another one, how to set it to a certain variant and got this far - [EDIT] after the first answer I got a bit further but I still have no idea how to loop through my results and put them into the next Report submit:
DATA: t_list TYPE TABLE OF abaplist.
* lt_seltab TYPE TABLE OF rsparams,
* ls_selline LIKE LINE OF lt_seltab.
SUBMIT Y5000114
USING SELECTION-SET 'MA OPLAN TEST'
EXPORTING LIST TO MEMORY
AND RETURN.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
listobject = t_list
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
WRITE 'Unable to get list from memory'.
ELSE.
* I want to fill ls_seltab here with all pernr (table pa0020) but I haven't got a clue how to do this
* LOOP AT t_list.
* WRITE /t_list.
* ENDLOOP.
SUBMIT Y5000114
* WITH-SELECTION-TABLE ls_seltab
USING SELECTION-SET 'MA OPLAN TEST2'
AND RETURN.
ENDIF.
P.S.
I'm not very familiar with ABAP so if I didn't provide enough Information just let me know in the comments and I'll try to find out whatever you need to know in order to solve this.
Here's my imaginary JS-Code that can express very generally what I'm trying to accomplish.
function submitAndReturnExport(Reportname,VariantName,OptionalPernrSelection)
{...return resultObject;}
var t_list = submitAndReturnExport("Y5000114","MA OPLAN TEST");
var pernrArr = [];
for (var i in t_list)
{
pernrArr.push(t_list[i]["pernr"]);
}
submitAndReturnExport("Y5000114","MA OPLAN TEST2",pernrArr);

It's not that easy as it supposed to, so there won't be any one-line snippet. There is no standard way of getting results from report. Try EXPORTING LIST TO MEMORY clause, but consider that the report may need to be adapted:
SUBMIT [report_name]
WITH SELECTION-TABLE [rspar_tab]
EXPORTING LIST TO MEMORY
AND RETURN.
The result of the above statement should be read from memory and adapted for output:
call function 'LIST_FROM_MEMORY'
TABLES
listobject = t_list
EXCEPTIONS
not_found = 1
others = 2.
if sy-subrc <> 0.
message 'Unable to get list from memory' type 'E'.
endif.
call function 'WRITE_LIST'
TABLES
listobject = t_list
EXCEPTIONS
EMPTY_LIST = 1
OTHERS = 2
.
if sy-subrc <> 0.
message 'Unable to write list' type 'E'.
endif.
Another (and more efficient approach, IMHO) is to gain access to resulting grid via class cl_salv_bs_runtime_info. See the example here
P.S. Executing the same report with different parameters which are mutually-dependent (output pars of 1st iteration = input pars for the 2nd) is definitely a bad design, and those manipulations should be done internally. As for me one'd better rethink the whole architecture of the report.

Related

Inserting name into database, getting korean signs as output

Trying to insert simple xml file with one row in IIB with simple message flow into Oracle XE DB. Message flow works fine and inserts data into database, but data written in db is different from starting data. For example, as I'm trying to insert my name "Dino" I'd get Korean/Japanese/Chinese signs in return.
I've tried changing XML formats thinking there might be problem, but I suppose it has to do with encoding.
Input:
Output in DB:
This is how my compute node looks like:
CREATE COMPUTE MODULE SimpleDB_mf_Compute
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
CALL CopyMessageHeaders();
-- CALL CopyEntireMessage();
INSERT INTO Database.dkralj.emp VALUES(InputRoot.XMLNSC.emp.name);
SET OutputRoot.XMLNSC.DBINSERT.STATUS='SUCCESS';
RETURN TRUE;
END;
CREATE PROCEDURE CopyMessageHeaders() BEGIN
DECLARE I INTEGER 1;
DECLARE J INTEGER;
SET J = CARDINALITY(InputRoot.*[]);
WHILE I < J DO
SET OutputRoot.*[I] = InputRoot.*[I];
SET I = I + 1;
END WHILE;
END;
CREATE PROCEDURE CopyEntireMessage() BEGIN
SET OutputRoot = InputRoot;
END;
END MODULE;
Looking at the IBM documentation for the INSERT statement in ESQL it might be worth trying.
INSERT INTO Database.dkralj(NAME) VALUES(InputRoot.XMLNSC.emp.name);
If weird things are still happening then I'd try a string constant to avoid any issues with character coding in the input message.
INSERT INTO Database.dkralj(NAME) VALUES('TheEmpValue');
Before this statement in your code
SET OutputRoot.XMLNSC.DBINSERT.STATUS='SUCCESS';
You should check for success or otherwise by using the inbuilt SQLSTATE, SQLCODE, SQLERRORTEXT to check the result of your call.
IF NOT ((SQLCODE = 0) OR (SQLSTATE = '01000' AND SQLNATIVEERROR = 8153)) THEN
-- Do something about the error.
-- The check of SQLSTATE and SQLNATIVEERROR covers warnings
-- The 8153 is for Microsoft SQL Server other databases may use a different value
END IF;
Also check the codepages aka CodedCharSetId of the source system data, the message in IIB and the default codepage of the database.
Use mqsicvp MYBROKER -n ODBC_DB_NAME to get other details about the connection you need to use -n to get the details.
Use something like DBeaver to add some data. Have a look at the datatype specified for the field.
As per your comment below and my response here is an example of a PASSTHRU statement. Note the use of the ? to avoid SQL Injection.
PASSTHRU('SELECT RTRIM(A.EMPLID) AS EMPLID,
RTRIM(A.ADDRESS_TYPE) AS ADDRESS_TYPE,
RTRIM(A.ADDR_TYPE_DESCR) AS ADDR_TYPE_DESCR,
CAST(RTRIM(A.EFFDT) AS DATE) AS EFFDT,
RTRIM(A.EFF_STATUS) AS EFF_STATUS,
RTRIM(A.ADDRESS1) AS ADDRESS1,
RTRIM(A.ADDRESS2) AS ADDRESS2,
RTRIM(A.ADDRESS3) AS ADDRESS3,
RTRIM(A.ADDRESS4) AS ADDRESS4,
RTRIM(A.CITY) AS CITY,
RTRIM(A.STATE) AS STATE,
RTRIM(A.POSTAL) AS POSTAL
FROM ADDRESS_VW AS A
WHERE UPPER(A.EMPLID) = ?') VALUES(AggrRef.EmployeeID)

How to exclude multiple values in OData call?

I am creating a SAPUI5 application. This application is connected to a backend SAP system via OData. In the SAPUI5 application I use a smart chart control. Out of the box the smart chart lets the user create filters for the underlying data. This works fine - except if you try to use multiple 'not equals' for one property. Is there a way to accomplish this?
I found out that all properties within an 'and_expression' (including nested or_expressions) must have unique name.
The reason why two parameters with the same property don't get parsed into the select options:
/IWCOR/CL_ODATA_EXPR_UTILS=>GET_FILTER_SELECT_OPTIONS takes the expression you pass and parses it into a table of select options.
The select option table returned is of type /IWCOR/IF_ODATA_TYPES=>EDM_SELECT_OPTION_T which is a HASHED TABLE .. WITH UNIQUE KEY property.
From: https://archive.sap.com/discussions/thread/3170195
The problem is that you cannot combine NE terms with OR. Because both parameters after the NE should not be shown in the result set.
So at the end the it_filter_select_options is empty and only the iv_filter_string is filled.
Is there a manual way of facing this problem (evaluation of the iv_filter_string) to handle multiple NE terms?
This would be an example request:
XYZ/SmartChartSet?$filter=(Category%20ne%20%27Smartphone%27%20and%20Category%20ne%20%27Notebook%27)%20and%20Purchaser%20eq%20%27CompanyABC%27%20and%20BuyDate%20eq%20datetime%272018-10-12T02%3a00%3a00%27&$inlinecount=allpages
Normally I want this to exclude items with the category 'Notebook' and 'Smartphone' from my result set that I retrieve from the backend.
If there is a bug inside /iwcor/cl_odata_expr_utils=>get_filter_select_options which makes it unable to treat multiple NE filters of the same component, and you cannot wait for an OSS. I would suggest to wrap it inside a new static method that will make the following logic (if you will be stuck with the ABAP implementation i would try to at least partially implement it when i get time):
Get all instances of <COMPONENT> ne '<VALUE>' inside a () (using REGEX).
Replace each <COMPONENT> with <COMPONENT>_<i> so there will be ( <COMPONENT>_1 ne '<VALUE_1>' and <COMPONENT>_2 ne '<VALUE_2>' and... <COMPONENT>_<n> ne '<VALUE_n>' ).
Call /iwcor/cl_odata_expr_utils=>get_filter_select_options with the modified query.
Modify the rt_select_options result by changing COMPONENT_<i> to <COMPONENT> again.
I can't find the source but I recall that multiple "ne" isn't supported. Isn't that the same thing that happens when you do multiple negatives in SE16, some warning is displayed?
I found this extract for Business ByDesign:
Excluding two values using the OR operator (for example: $filter=CACCDOCTYPE ne ‘1000’ or CACCDOCTYPE ne ‘4000’) is not possible.
The workaround I see is to select the Categories you actively want, not the ones you don't in the UI5 app.
I can also confirm that my code snippet I've used a long time for filtering also has the same problem...
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_MGW_ABS_DATA->FILTERING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_TECH_REQUEST_CONTEXT TYPE REF TO /IWBEP/IF_MGW_REQ_ENTITYSET
* | [<-->] CR_ENTITYSET TYPE REF TO DATA
* | [!CX!] /IWBEP/CX_MGW_BUSI_EXCEPTION
* | [!CX!] /IWBEP/CX_MGW_TECH_EXCEPTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD FILTERING.
FIELD-SYMBOLS <lt_entityset> TYPE STANDARD TABLE.
ASSIGN cr_entityset->* TO <lt_entityset>.
CHECK: cr_entityset IS BOUND,
<lt_entityset> IS ASSIGNED.
DATA(lo_filter) = io_tech_request_context->get_filter( ).
/iwbep/cl_mgw_data_util=>filtering(
exporting it_select_options = lo_filter->get_filter_select_options( )
changing ct_data = <lt_entityset> ).
ENDMETHOD.

TT X-trader API

Does anyone know how to query TT X-trader API to figure out if an order ( given order site-key ) is in the market?
Currently I'm doing a lookup on the siteKey, which should return an order object.
However, if the order is no longer in the market, an exception is thrown, which in MATLAB can be caught with a try|catch syntax.
try
...
ttOrderSet = xtrdr.OrderSet;
ttOrderObj = ttOrderSet.SiteKeyLookupEx( siteKey );
... % order is in the market
catch
... % Order isn't in the market
end
Problem with this mechanism is that I have bugs elsewhere in my code that need a breakpoint and this piece of code automatically causes a breakpoint to occur, which means that it unnecesarily stops everytime I query the order.
I'm sure a function exists such that one can query whether the order is live in the market or not.

Cumulocity epr differences with esper

I was testing some rules I wrote in Cumulocity, and as I couldn't get the results I wanted I tried using the Esper EPL online tool for comparison. Turns out I found a difference in outputs between the two that I can't explain.
Basically, what I want to do is create a context partitionned by source and delimited by "start" and "stop" events. Then when my context ends, I want to display some details (type and time) from my starting and ending events only (I don't care for the events in between at the moment).
Here's my rule (the create schema have to be removed for Cumulocity because they are already defined "natively"):
create schema EventCreated(
source String,
type String,
time Date
);
create schema CreateMeasurement(
source String,
type String,
time Date,
fragments Object
);
#Name("create_context")
create context Trip
context bySource
partition by source from EventCreated,
context byEvents
start EventCreated(
type = "c8y_ObdConnectionReport" or
type = "c8y_PowerOnReport" or
type = "c8y_FixedReport" or
type = "c8y_HarshBehaviorReport") as startEvent
end EventCreated(
type = "c8y_ObdDisconnectionReport" or
type = "c8y_PowerOffReport" or
type = "c8y_SilentTracker") as endEvent;
#Name("context_end")
context Trip
insert into
CreateMeasurement
select
context.bySource.key1 as source,
"Trip" as type,
e.time as time,
{
"startedBy", context.byEvents.startEvent.type,
"startedAt", context.byEvents.startEvent.time,
"endedBy", e.type,
"endedAt", e.time
} as fragments
from
EventCreated e
output
last when terminated;
And here is a simple event sequence to see the difference:
EventCreated = {
source = '1672192',
type = 'c8y_ObdConnectionReport',
time = '2016-10-07T10:00:00.000'
}
t = t.plus(5 minutes)
EventCreated = {
source = '1672192',
type = 'c8y_FixedReport',
time = '2016-10-07T10:05:00.000'
}
t = t.plus(5 minutes)
EventCreated = {
source = '1672192',
type = 'c8y_ObdDisconnectionReport',
time = '2016-10-07T10:10:00.000'
}
So here is the result using the EPL online simulatior:
At: 2016-10-07 10:05:00.000
Statement: context_end
Insert
CreateMeasurement={
source='1672192',
type='Trip',
time='2016-10-07T10:05:00.000',
fragments[
'startedBy','c8y_ObdConnectionReport',
'startedAt','2016-10-07T10:00:00.000',
'endedBy','c8y_ObdDisconnectionReport',
'endedAt','2016-10-07T10:10:00.000']}
This is what I want, I got details from my first and last event as expected. Now this is what I get with Cumulocity:
{
"source":{
"id":"1672192",
"name":"Tracker 123456789000000",
"self":"http://tracker.post-iot.lu/inventory/managedObjects/1672192"},
"type":"Trip",
"time":"2016-10-25T11:56:46.983+02:00",
"self":"http://tracker.post-iot.lu/measurement/measurements/null",
"startedBy":"c8y_ObdConnectionReport",
"startedAt":"2016-10-25 11:56:44+0200",
"endedBy":"c8y_FixedReport",
"endedAt":"2016-10-25 11:56:46+0200"
}
(Disregard the dates, I'm working real-time with Cumulocity).
As you can see, it considers the last event to be the FixedReport instead of the DisconnectionReport. So what basically happens in Cumulocity (I've tried various situations), is that the ending event of the context is disregarded every time, so I can only retrieve the next-to-last event.
Whis this difference with the Esper engine? How can I do do make this work like I think it should?
It is probably accidental issue that esper online tool always handle last event but cumulocity - one before last.
Which case occurs depends on which statement ("create_context or "context_end") will be executed first. However the order of statements execution is random unless #Priority annotation is provided.
According to the note in esper documentation (http://www.espertech.com/esper/release-5.3.0/esper-reference/html/context.html#context_def_nonoverlapping)
If you specified an event filter or pattern as the end condition for a context partition, and statements that refer to the context specify an event filter or pattern that matches the same conditions, use #Priority to instruct the engine whether the context management or the statement evaluation takes priority (see below for configuring prioritized execution).
For example, if your context declaration looks like this:
create context MyCtx start MyStartEvent end MyEndEvent
And a statement managed by the context is this:
context MyCtx select count(*) as cnt from MyEndEvent output when terminated
By using #Priority(1) for create-context and #Priority(0) for the counting statement the counting statement does not count the last MyEndEvent since context partition management takes priority.
By using #Priority(0) for create-context and #Priority(1) for the counting statement the counting statement will count the last MyEndEvent since the statement evaluation takes priority.
Fix: add #Priority(0) to "create_context" statement and #Priority(1) to "context_end" statement.

How can you join two or more dictionaries created by Bio.SeqIO.index?

I would like to be able to join the two "dictionaries" stored in "indata" and "pairdata", but this code,
indata = SeqIO.index(infile, infmt)
pairdata = SeqIO.index(pairfile, infmt)
indata.update(pairdata)
produces the following error:
indata.update(pairdata)
TypeError: update() takes exactly 1 argument (2 given)
I have tried using,
indata = SeqIO.to_dict(SeqIO.parse(infile, infmt))
pairdata = SeqIO.to_dict(SeqIO.parse(pairfile, infmt))
indata.update(pairdata)
which does work, but the resulting dictionaries take up too much memory to be practical for for the sizes of infile and pairfile I have.
The final option I have explored is:
indata = SeqIO.index_db(indexfile, [infile, pairfile], infmt)
which works perfectly, but is very slow. Does anyone know how/whether I can successfully join the two indexes from the first example above?
SeqIO.index returns a read-only dictionary-like object, so update will not work on it (apologies for the confusing error message; I just checked in a fix for that to the main Biopython repository).
The best approach is to either use index_db, which will be slower but
only needs to index the file once, or to define a higher level object
which acts like a dictionary over your multiple files. Here is a
simple example:
from Bio import SeqIO
class MultiIndexDict:
def __init__(self, *indexes):
self._indexes = indexes
def __getitem__(self, key):
for idx in self._indexes:
try:
return idx[key]
except KeyError:
pass
raise KeyError("{0} not found".format(key))
indata = SeqIO.index("f001", "fasta")
pairdata = SeqIO.index("f002", "fasta")
combo = MultiIndexDict(indata, pairdata)
print combo['gi|3318709|pdb|1A91|'].description
print combo['gi|1348917|gb|G26685|G26685'].description
print combo["key_failure"]
In you don't plan to use the index again and memory isn't a limitation (which both appear to be true in your case), you can tell Bio.SeqIO.index_db(...) to use an in memory SQLite3 index with the special index name ":memory:" like so:
indata = SeqIO.index_db(":memory:", [infile, pairfile], infmt)
where infile and pairfile are filenames, and infmt is their format type as defined in Bio.SeqIO (e.g. "fasta").
This is actually a general trick with Python's SQLite3 library. For a small set of files this should be much faster than building the SQLite index on disk.

Resources