Skip to Content
0

How to make association to BO Material to get the Description.

Jul 11, 2017 at 03:45 PM

265

avatar image

Hi,

I created custom BO with an association to BO Material.

I also made OVS for field Material ID (which works) and another field Material Description (which does not work, the value does not appear in it).

I tried to make everything by analogy with the Employee association in Car Park example.

node MaterialCosts [0,n] {
element Item			: LANGUAGEINDEPENDENT_MEDIUM_Name;
element MaterialID		: ID;
element MaterialDescription	: LANGUAGEINDEPENDENT_MEDIUM_Name;
element BaseQuantity		: Quantity;
element NoOfPiecePerPack	: Quantity;
element ScrapRate		: Percent;
element Overhead		: Percent;
element TotalQuantity		: Quantity;
element UnitCost		: Amount;
element UoM			: MeasureUnitCode;
element Cost			: Amount;
association ToMaterial [0,1] to Material;
}

What could be the cause?

I see cardinality [0,n] in node Description, is it possible such binding principally?

Or there may be some workaround.

Thank you.

000074.jpg (92.8 kB)
10 |10000 characters needed characters left characters exceeded
* Please Login or Register to Answer, Follow or Comment.

6 Answers

Best Answer
Senthil Murugan Jul 12, 2017 at 08:11 AM
0

Hi Aleksi,

You have to associate through ABSL code.

something like,

if(!this.ToMaterial.IsSet()){
var materialIns = Material.Retrive(this.MaterialID);// you can use query as well.
if(materialIns.IsSet())
{
this.ToMaterial = materialIns;
}
}

Regards

Senthil

Share
10 |10000 characters needed characters left characters exceeded
Aleksei BELOUSOV Jul 13, 2017 at 08:42 PM
1

Yet I have found out why the association to Employee in my example did not work.

It appeared there was a need to add some supporting ABSL code in Event-AfterModify .

It is just the spot where element ToEmployee is assigned.

Eventually, final example (after some simplification) looks so

BO:

import AP.Common.GDT as apCommonGDT;
import AP.FO.BusinessPartner.Global;
import AP.FO.ProductDataMaintenance.Global;

businessobject OVS {
		element EmployeeID : EmployeeID;
		element GivenName2 : LANGUAGEINDEPENDENT_MEDIUM_Name;
		association ToEmployee[0,1] to Employee;

		element MaterialID : ProductInternalID;
		element Description2 : LANGUAGEINDEPENDENT_MEDIUM_Name;
		association ToMaterial[0,1] to Material;
}

Event-AfterModify:

//	Event: AfterModify 
import ABSL;
import AP.FO.BusinessPartner.Global;
import AP.FO.ProductDataMaintenance.Global;

// Given Name
// --- cut from CarPark example ---
// Auxiliary flag that will help us decide whether we have to update the ToEmployee association.
var bUpdateEmployee = false;
// Our pointer to the employees' query.
var qryEmployees;
// Object that will hold the parameters for our employees' query call.
var paramEmployee;
// Collection of result values of our employees' query call.
var resultEmployees;
// Check whether our ToEmployee association is still up to date. If not, we'll have to update it.
if (this.EmployeeID.IsInitial()) {
	// => No employee indicated for the parking space.
	if (this.ToEmployee.IsSet()) {
		// => Our ToEmployee association still holds the employee that had been
		// associated before - so now we have to reset the association.
		this.ToEmployee.Reset();
	}
}
else if (!this.ToEmployee.IsSet()) {
	// => We do have an employee indicated for the parking space, however,
	// the association ToEmployee hasn't been initialized, yet.
	// => Set our flag to true.
	bUpdateEmployee = true;
}
else if (this.ToEmployee.IdentificationEmployeeID.EmployeeID.content != this.EmployeeID.content ) {
	// => We do have an employee indicated for the parking space, however,
	// the association ToEmployee still holds the employee that had been associated to the space before.
	// => Set our flag to true.
	bUpdateEmployee = true;
}
if (bUpdateEmployee) {
	// => Our association to the employee needs to be refreshed.
	// Reset it first, since the new employee ID might be invalid.
	this.ToEmployee.Reset();
	// Now look for the details of the given employee:
	// ...connect to the BO Employee's query...
	qryEmployees = Employee.Identification.QueryByEmployeeAttributes;
	// ...populate the parameters collection for the query call...
	paramEmployee = qryEmployees.CreateSelectionParams();
	// ...saying that the ID of the employee we're looking for must be the ID indicated by our user...
	paramEmployee.Add(qryEmployees.EmployeeID.content, "I", "EQ", this.EmployeeID.content);
	// ...and execute the query!
	resultEmployees = qryEmployees.Execute(paramEmployee);
	// Hopefully we've found an employee to the given ID!
	foreach (var oneEmployee in resultEmployees) {
		// Since we know that we can have only one employee to the ID, we
		// take the first result and exit the loop.
		this.ToEmployee = oneEmployee.ToRoot;
		break;
	}
}
// --- cut from CarPark example ---


// Given Name 2
var employeeidentification = Employee.Identification.Retrieve ( this.EmployeeID );
if ( employeeidentification.IsSet() ) {
	this.GivenName2 = employeeidentification.ToParent.CurrentCommon.Person.Name.GivenName;
} else {
	this.GivenName2.Clear();
}

// Description (not implemented)


// Description 2
var material = Material.Retrieve ( this.MaterialID );
if ( material.IsSet() ) {
	this.Description2 = material.Description.GetFirst().Description.content;
} else {
	this.Description2.Clear();
}

return;

Result:

It seems everything works properly now.

Best regards,

Aleksei


000077.jpg (24.3 kB)
Share
10 |10000 characters needed characters left characters exceeded
Aleksei BELOUSOV Jul 12, 2017 at 10:38 AM
0

Thank you, Senthil,

As far as I understand this code should be put in After-Modify event?

I thought over such a way to remove association at all (there will not be a need the association in this case) and just to retrieve Description with a query (it is a common practice in ABAP). Only I am not sure about performance in ByD as a web application. But I will try that anyway.

Thank you.

Aleksei

Show 1 Share
10 |10000 characters needed characters left characters exceeded

Yes Aleksei,

Association always cost performance, If showing description for any material ID is your only goal, I would suggest add one more element in the BO and assign the description to it. so that you can cut the performance cost.

Regards,

Senthil.

0
Aleksei BELOUSOV Jul 13, 2017 at 08:13 AM
0

Thank you, Senthil,

I tried getting data with using ABSL, and it works quite fast.

There is a workable example I have made to get GivenName for Employee and Description for Material

BO:

import AP.Common.GDT as apCommonGDT;
import AP.FO.BusinessPartner.Global;
import AP.FO.ProductDataMaintenance.Global;

businessobject OVS {

		element EmployeeID : EmployeeID;
		element GivenName2 : LANGUAGEINDEPENDENT_MEDIUM_Name;
		association ToEmployee[0,1] to Employee;


		element MaterialID : ProductInternalID;
		element Description2 : LANGUAGEINDEPENDENT_MEDIUM_Name;
		association ToMaterial[0,1] to Material;


		node Employees[0,n] {
			element Workplace : ID;
			element EmployeeID : ID;
			association ToEmployee[0,1] to Employee;
		}
}

Event-AfterModify.absl:

*
	Add your SAP Business ByDesign scripting language implementation for:
		Business Object: OVS
		Node: Root
		Event: AfterModify 
		
	Note: 
	  - To access the elements of the business object node, 
	    use path expressions, for example, this.<element name>. 
	  - To use code completion, press CTRL+J. 
	  - The solution uses this script if:
		- the value of any field in the node in which this script is contained is modified.
		- the node itself is modified by another business object within the same solution.
*/


import ABSL;
import AP.FO.BusinessPartner.Global;
import AP.FO.ProductDataMaintenance.Global;

var employeeidentification = Employee.Identification.Retrieve ( this.EmployeeID );
if ( employeeidentification.IsSet() ) {
	this.GivenName2 = employeeidentification.ToParent.CurrentCommon.Person.Name.GivenName;
} else {
	this.GivenName2.Clear();
}


var material = Material.Retrieve ( this.MaterialID );
if ( material.IsSet() ) {
	this.Description2 = material.Description.GetFirst().Description.content;
} else {
	this.Description2.Clear();
}


return;

QA screen:

As far as we can see Given Name and Description implemented with the association are populated neither in the Root node nor in the Employees node. I have no idea why the Employee association has stopped working. I have made the example according to Car Park example exactly. ABSL implemented Given Name 2 and Description 2 work properly and do not need the associations at all.

Thank you.

Aleksei


000075.jpg (45.6 kB)
Share
10 |10000 characters needed characters left characters exceeded
Aleksei BELOUSOV Jul 13, 2017 at 09:00 AM
0

Thank you, Horst, for useful information.

Unfortunately, now associations do not work in my example, even the Employee association has stopped working. It keeps working normally in my old Car Park examples, though. I have no idea what the cause is.

I have read the blog but, unfortunately, so far I could not realise where the filter for the association is.

It is not quite clear to me how associations work in general - how a master field is chosen to link with associated BO.

For example, if we have both Employee1 : ID and Employee2 : ID elements in our BO what element will be chosen as a master key for the association ToEmployee? Where could I see this binding in properties?

Besides that, I seem there is a small typo in Cloud Application Studio documentation (studio_od_1611.pdf, studio_od_1702.pdf) a picture on page 96 in the Car Park example. I rounded it.

Probably it should be CurrentCommon. If so, please, fix it in next version of the manual. Everything is correct in the document text, though.

Thank you.

Aleksei


000076.jpg (27.3 kB)
Show 4 Share
10 |10000 characters needed characters left characters exceeded

Hello Aleksi,

If you define in your BODL

association ToEmployee to AP.BusinessPartner.Global:Employee;

then a new element is added to the BO model which contains the resp. key to determine the target. Any other element is not used here (by the system).
Of course you can add ABSL coding which determines from the "Employee1" element the resp. instance of the BO. But then you also need to assign the reference to the association.

HTH,
. Horst

0

Thank you, Horst,

In that case, I do not understand quite well how the value in ToEmployee is changed if we change the value in field EmployeeID - OVS bound to EmployeeID (which is a field of Object Value Selector type), not ToEmployee.

Is there a way to see the properties of ToEmployee?

Thank you,

Aleksei

0

Hello Aleksei,

What is the return of the OVS? -> the EmployeeID
Therefore you need an ABSL script AfterModify (or an action) which derives the node instance from the new value and set it to the association.

Please check by yourself in the documentation at section 5.8.2.2 " Sample Code: Event-AfterModify CarPark-ParkingSpace"

HTH,
. Horst

0

Hello Horst,

Thank you. Yes, it is just the cause why my example did not work.

I forgot to create ABSL script for the association.

Now everything is OK. I have figured out how associations work.

Best regards,

Aleksei

0
Horst Schaude
Jul 12, 2017 at 12:36 PM
0

Hello Aleksi

From your statement

"OVS for field Material ID (which works) and another field Material Description (which does not work)"

I assume its the OVS which returns values for the ID but no for the description.

This is because - as you already suggest - the association to the Description node is a 1-to-many. This means it returns a list of descriptions (in different languages).

Have a look at this blog.

There is a filter for this association in which you can provide the language. Then only one value is returned and the OVS should work.

HTH,
. Horst

Share
10 |10000 characters needed characters left characters exceeded