cancel
Showing results for 
Search instead for 
Did you mean: 

Generic UDF to handle empty contexts and contexts with missing fields

KennethEriksen
Participant
0 Kudos

Hi,

I have been trying to get my head around a UDF for this for a while, but cannot find the solution. I''l start by showing input structure, and expected target structure (subset of an invoice IDoc with 4 line items):

SOURCE:

E1EDK01 (0..1)

E1EDP01

---POSEX = 1

---E1EDP05

-


KOTXT (qualifier) = Z1

-


BETRG (amount) = 200,00

---E1EDP05

-


KOTXT = Z2

-


BETRG = 300,00

---E1EDP19...

E1EDP01

---POSEX = 2

---E1EDP05

-


KOTXT = Z1

---E1EDP05

-


KOTXT = Z2

-


BETRG = 400,00

---E1EDP19...

E1EDP01

---POSEX = 3

---E1EDP05

-


KOTXT = Z2

-


BETRG = 500,00

---E1EDP19...

E1EDP01

---POSEX = 4

---E1EDP19...

TARGET:

Line

---PosId = 1

---Price = 200.00

Line

---PosId = 2

---Price = N/A

Line

---PosId = 3

---Price = N/A

Line

---PosId = 4

---Price = N/A

I want the price from E1EDP05/BETRG where KOTXT = Z1to be set for each line. As you can see the source structure can be split in 4 cases:

1. for some line items there exist multiple E1EDP05-segments with one of them qualifier Z1 and one corresponding amount field. This is the "perfect" structure and easy to handle.

2. some line items contains E1EDP05 with qualifier Z1 with no BETRG. Problem-case

3. some line items contains no E1EDP05-segments with qualifier Z1, but contains other E1EDP05-segments. Can be solved.

4. some line items contains no E1EDP05-segments at all. Can be solved.

I need to (I believe) set the context of the KOTXT and BETRG to E1EDP01 since I want one value per line item, irrespective of how many E1EDP05-segments exist per line item. In cases where no value can be found for relevant qualifier (Z1) or no E1EDP05-segments exist for a line item I want a default value to be set (N/A).

My problem is that all these different cases might occur in the same file, and they mess up the values in each context, leading to wrong BETRG to be picked in some cases (where case 2 exist) since mapWithDefault cannot be used (context contains value for other qualifier).

Do you know how to handle all these cases?

Any pseudo-code for an UDF?

Many thanks for your help!

Br,

Kenneth

Accepted Solutions (1)

Accepted Solutions (1)

shweta_walaskar2
Contributor
0 Kudos

Hello Kenneth,

I had faced a similar problem.We had a requirement,such that based on value of KSCHL in EDP05,we had to populate a field in target structure.

I know,this is quite difficult as I had to spend a lot of time to resolve this.The solution was,to create a queue with SUPPRESS at appropriate places.

I can't assure you that the same solution works for you,but may be you can have a look

I have created a UDF addSUPPRESS (context function):

public void addSUPPRESS1(String[] a,String[] b,ResultList result,Container container){

int j=0;

AbstractTrace trace=container.getTrace();

for(int i=0;i<a.length;i++)

{

if(a<i>.equals("true"))

{

trace.addInfo("Hi");

result.addValue(b[j]);

result.addValue(ResultList.CC);

j=j+1;

}

else

{

result.addValue(ResultList.SUPPRESS);

}

}

This UDF takes two queues as input

1) a check if KOTXT=Z1 should return true or false(set the context of KOTXT to EDP01)

2) if then sequence which checks if KOTXT=Z1 then BETRAG (don't change the context of KOTXT and BETRG,should be EDP05),put a removeContexts function after the resulting queue having BETRAG values

Now you have two queues, first having values true or false without context change and other having relevant BETRAG values again without context change.

When these queues are passed as parameters to UDF addSUPPRESS,the output is a queue having multiple SUPPRESSES in correct sequence.

Apply a splitbyValue function and map the result to your target field.

I don't know how to attach screenshot here,otherwise it would have been more easier to explain.

Hope it works for you as well.

Thanks.

Regards,

Shweta

KennethEriksen
Participant
0 Kudos

Hi Shweta!

Thanks a lot, your idea didn't completely solve my problem, but pointed me in the right direction and gave me some valuable ideas:)

For anyone wondering how it is done, I solved it by using your suggested two inputs, along with a third input (constant) which functions as default value for contexts where value-field is missing for a specific qualifier, or in case no segments with desired qualifier exists for a context.

My mapping now looks like the following (where KOTXT is qualifier and KRATE is value field) for the 3 inputs:

KOTXT(Context = E1EDP01) \
                            equalsS -->
Constant(qualifier value) /

KOTXT(Context = E1EDP05) \
                            equalsS  \
Constant(qualifier value) /            ifWithoutElse --> removeContexts -->
           KRATE (Context = E1EDP05) /

Constant(default value) -->

Then these 3 inputs goes into the following UDF (queue function):

int j=0;
boolean contextDone = false;
for(int i=0;i<a.length;i++) 
{ 
	if(a<i>.equals("true")) 
	{
		if(b[j].equals(ResultList.SUPPRESS)) 
		{
			result.addValue(c[0]);
		} 
		else 
		{
			result.addValue(b[j]);
		}
		contextDone = true;
		j=j+1;
	}
	if(a<i>.equals(ResultList.CC)) 
	{
		if (contextDone) 
		{
			contextDone = false;
			result.addValue(ResultList.CC);
		}
		else 
		{
			result.addValue(c[0]);
			result.addValue(ResultList.CC);
		}	
	}
}

This results in a target node created for each context, where context relates to each line item in this case, where each value is either a default value or the value corresponding to the qualifier. This works in all cases where:

1. there are no segments containing relevant qualifier

2. there are segments with relevant qualifier, but missing value field

3. there are segments with relevant qualifier and value field

Thanks a lot again, Shweta, for guiding me!

Br,

Kenneth

Answers (1)

Answers (1)

former_member181962
Active Contributor
0 Kudos

Hi Kenneth,

I think there is no need for a UDF here.

Just set the context of the KOTXT and BETRG as E1EDP01.

Check for condition, if KOTXT = 'Z1', then pass BETRG->mapWithDefault(N/A)-> Output field

Regards,

Ravi

KennethEriksen
Participant
0 Kudos

Hi,

Thanks for your input, but this will return wrong values for case 2 (line item 2 in example). Here the mapWithDefault for BETRG will not execute since the context already contains the BETRG for qualifier Z2 (since we set context to E1EDP01). This leads to the wrong BETRG being picked (BETRG for qualifier Z2 since this now matches the index of the qualifier Z1).

-Kenneth

former_member181962
Active Contributor
0 Kudos

Hi Kenneth,

While someone else comes up with a neater alternative, you can try the follwoing.

Somewhere in the starting of the mapping, you can use the Concatenation of ITEMNUMBERKOTXTBETRG and use setParameter to set a the value , and later use getParamater function to retrieve tha value .

Read more about global variables here:

http://help.sap.com/saphelp_nw04/helpdata/EN/75/8e0f8f3b0c2e4ea5f8d8f9faa9461a/content.htm

Alternatively, you can ask your ABAPer not to populate KOTXT when there is no value for BETRG in E1EDP05

Regards,

Ravi

KennethEriksen
Participant
0 Kudos

Thanks, I'm aware of the possibility to either remove KOTXT or add BETRG for all segments using ABAP, but I was hoping to make a generic function/solution to this which can be used for all scenarios where there are repeating segments with qualifiers. This way I don't have to write ABAP for every single field/segment where this situation can occur.

I do not quite get how global variables will help, I guess I would still have problem concatenating the correct values from the different input-queues considering contexts and possible missing values. Can you elaborate a bit more how this would work?

Thanks!