Cool Solutions

IDM Driver for SAP-HR, Getting the Manager from the OU Objects.



By:

November 14, 2008 2:24 pm

Reads:5,003

Comments:0

Score:5

The fact that you can actually set manager and directReports relations in an Identity Vault form information coming from HR drivers is probably one of the coolest features of these drivers.

These relations can be used in workflows, org charts mail notification etc, and you do not want to set this manually, especially in large environments.

But every now and then it is very hard to get this information. The SAP-HR driver is one of those, it works great but sometimes people cannot get it to work. There are even some discussions on the Novell Forums about getting manager information in the SAP-HR driver. Sometimes people can’t do the query, sometimes there’s no or little result. But in all cases it is very hard to understand why.

The Novell documentation is absolutely correct on the special transitions and queries that are done in the default driver setup. There is however very little explanation on what the result might be and what to do if it does not work.

In this article I want to provide another way to get this information from SAP when the default configuration does not work. Because the information is there, but simply in another format.

The attachment contains the Stylesheet with the complete code. I am of course available for any improvements.

Lets start off with a short explanation on the possibilities of the queries.

As you follow the guidelines from the documentation you need to do an export from SAP for all object in a specific order.

First the “O” objects. The driver will add some attributes by default on the synchronized objects (Organizational), but it does not do anything with manager-directReports relations.

Then the “C” objects (Commexec) are supposed to be imported. These are important for setting Title like attributes on the user, but again, there are no manager-directReports relations.

After that the “S” object (organizational Roles) are imported and that’s where the magic starts.

    There are four templates in the Publisher Command Transform Stylesheet that will handle these objects: With “current organizational role” I mean the object that is coming into the channel.

  1. xsl:template name=”set-roles-manager-attr”>This template sets the manager attribute on the current organizational role if available.
  2. xsl:template name=”set-roles-directReports-attr”>This template sets one or more directReports attribute on the current organizational role if available.
  3. xsl:template name=”set-roles-managers-directReports”>This template sets the directReports attribute on the manager object from the current organizational role. So it is the modification of another object.
  4. xsl:template name=”set-roles-directReports-manager”>This template sets the manager attribute on all directreports objects from the current organizational role if available. So this is also the modification of another object(s).

The result after reading all objects will be a complete organizational structure hidden within the organizational Roles.

Last but not least the “P” objects (Users) are imported. The same stylesheet will link the user to an organizational role to get the manager role and use the occupant from this role to set the manager.

The real magic is how the driver finds this information. Well it is simply embedded within the iDoc’s.

A query is started to the channel source (iDoc’s). When I want to know what is inside the iDoc’s I always copy the following code to make a query that will give me all in a level 3 trace.

		<xsl:variable name="query">
			<nds dtdversion="1.0" ndsversion="8.5">
				<input>
					<query class-name="RELATIONSHIPS" event-id="0" scope="entry">
						<association>
							<xsl:value-of select="$newRole-ID"/>
						</association>
						<search-class class-name="S"/> <!-- or "O" -->
					</query>
				</input>
			</nds>
		</xsl:variable>

The result of this query will look like this:
(For the purpose of making this stuff readable I stripped all non relevant lines from the result.)

        <value type="structured">
          <component name="BEGDA">20040922</component>
          <component name="INFTY">1001</component>
          <component name="OTYPE">S</component>
          <component name="RELAT">002</component>
          <component name="ENDDA">99991231</component>
          <component name="SCLAS">S</component>
          <component name="RSIGN">A</component>
          <component name="SOBID">10000057</component>
          <component name="OBJID">10000150</component>
          <component name="VARYF">S 10000057</component>
        </value>
        <value type="structured">
          <component name="BEGDA">20060622</component>
          <component name="INFTY">1001</component>
          <component name="OTYPE">S</component>
          <component name="RELAT">002</component>
          <component name="ENDDA">99991231</component>
          <component name="SCLAS">S</component>
          <component name="RSIGN">B</component>
          <component name="SOBID">10000016</component>
          <component name="OBJID">10000150</component>
          <component name="VARYF">S 10000016</component>
          <component name="AEDTM">20060622</component>
        </value> 

Now let’s get the information I need by trimming down the query. So the actual queries look something like:

In the explanation of the stylesheet this query is referred with different values for the search attributes.

		<xsl:variable name="query">
			<nds dtdversion="1.0" ndsversion="8.5">
				<input>
					<query class-name="RELATIONSHIPS" event-id="0" scope="entry">
						<association>
							<xsl:value-of select="$newID"/>
						</association>
						<search-class class-name="S"/> <!-- or "O" or "P" -->
						<search-attr attr-name="RSIGN">
							<value>A</value>
						</search-attr>
						<search-attr attr-name="SCLAS">
							<value>S</value>
						</search-attr>
						<search-attr attr-name="RELAT">
							<value>012</value>
						</search-attr>
						<read-attr attr-name="SOBID"/>
					</query>
				</input>
			</nds>
		</xsl:variable>

Some explanation on the values in this query;

  • The variable newID is used to pass the current object to the query.
  • The element search-class class-name “S” is to specify the kind of object you are querying in.
  • The search attribute RSIGN provides the relation you are looking for:
  • —-A stands for “Bottom Up” so the query definition looks for “parents”
  • —-B stands for “Top down” so the query definition looks for “childs”
  • The search attribute SCLAS is need to specify the objecttype you’re looking for because there might be “K” objects (cost-heading) as well defined as a parent, and we don’t need those.
  • We can also use these queries on “O” type objects. You can find parent or child Organizational Units (RSIGN=A or B).
  • But we can also find the roles within a department. This would be the results where RELAT=003 (member) or RELAT=12 (manager).

The result query will contain records defined by the SOBID attribute.

This SOBID is the SAP objectID, and thus the association!!!! of the object you are looking for without the object-type character (O,C,S,P).

The default stylesheet also contains a “query-assoc-dn” templates. This is used to get the actual object DN given the association.(SOBID).

In conclusion, we can do almost all queries based on RSIGN, SCLAS, and RELAT but there is a lot more information hidden within the object.

However………,Sometimes…..

The information you want is simply not within the iDoc’s. The issue we see the most is that the relation between one “S” object and another “S” is (manager-directReports) is simply not there because it is not configured within SAP. We noticed however that the relational management within the “O” object is usually there by default.

So now we can use these objects to find the manager relation within a company.

Solution

Below you’ll find a solution that will do the trick. It contains one new stylesheet and an alteration on the existing one.

You can get the new stylesheet from the attachment.

First we strip all matches on “O” and “S” object type templates from the original Publisher Command Transform Stylesheet. Leave the rest like it is.

The only thing we left in the original stylesheet is the part on renaming “O” and “S” objects in the modify templates, these would interfere with other select statements in the new stylesheet.

Secondly we create a couple of auxiliary attributes to hold some extra information on Organizational Units and Roles. This is not always necessary but it will provide some easier management and … it is eDirectory, and that is scalable!!

The last step is to implement a new stylesheet, i.e. “Publisher Command Transform OrgChart Stylesheet”. Let me explain (you’ll find the whole sheet here):

We do a match match on ‘Organizational Role’ or ‘Organizational Unit’ from within the copy.

		<xsl:copy>
			<xsl:apply-templates select="@*"/>
			<xsl:apply-templates select="* | comment() | processing-instruction() | text() "/>
			<xsl:choose>		
				<xsl:when test="ancestor-or-self::add[@class-name='Organizational Role']">
				    <xsl:call-template name="check-if-roles-manager"/>
				    <xsl:call-template name="set-role-dept"/>
				    <xsl:call-template name="set-roles-manager-attr"/>
				    <xsl:call-template name="set-roles-directReports-attr"/>
				</xsl:when>
				<xsl:when test="ancestor-or-self::add[@class-name='Organizational Unit']">
				    <xsl:call-template name="set-manager-position"/>
				    <xsl:call-template name="set-member-position"/>
     		       	 	    <xsl:call-template name="set-parent-ou-position"/>
				    <xsl:call-template name="set-child-ou-position"/>
				</xsl:when>
			</xsl:choose>
		</xsl:copy>

Let’s start with the ‘Organizational Unit’

  • Within the first template called (“set-manager-position”) we set the manager position. This will be the SOBID, not a link to the object itself, because it might not there yet.
    So we query the “O” object with RSIGN=B(top-down, but not necessary), SCLAS=S (OR object) and RELAT=012 (manager for this department).

    The result is set in an auxiliary attribute

  • Within the second template (“set-member-position”) we set all members positions. This will be the SOBID, not a link to the object itself, because it might not be there yet.

    So we query the “O” object with RSIGN=B(top-down, but not necessary), SCLAS=S (OR object) and RELAT=003 (member for this department). This is for each because there is more than one member. The result is set in an auxiliary attribute

  • In the third template (“set-parent-ou-position”) we set the parent Organizational Unit position. This will also be the SOBID. So we query the “O” object with, SCLAS=O (OU object) and RSIGN=A (Bottom Up, thus the parent OU). The result is set in an auxilliary attribute
  • In the fourth template (“set-child-ou-position”) we set all the child Organizational Unit positions. This will also be the SOBID. So we query the “O” object with, SCLAS=O (OU object) and RSIGN=B , thus all the child OU). The result is set in an multi valued auxilliary attribute

We need the last two to find the manager for a manager, so we must look for the parent department.

Now let’s check the Organizational Roles themselves.

Remember, as soon as we have the manager-directReports in place at this level, the default Stylesheet will make sure that these relations are set on the user level.

Some of the following templates are not even needed, they are just handy in maintaining the code.

  • The first template (“check-if-roles-manager”) sets the isManager to true. It also places a dn reference on the current object to the OU object he is manager of.
    The query is done to an “S” object with RSIGN=A, SCLAS=O and RELAT=012.

    The value for this auxiliary attribute is found via the default “find object with assoc” and the SOBID that came back from the query.
  • The second query (“check-dept”)is pretty much the same, however it does not set the isManager. The difference is in the query, RELAT=003. And it will set the result (again a DN set to an auxiliary attribute).

If these two templates are finished, every Role has information of the department it belongs to.

  • The third template (“set-roles-manager-attr”) sets the manager attribute.

    First we check if the current object is a manager. (RELAT=012)
    *)If so it will query for the department for this manager. (RSIGN=A, SCLAS=O, RELAT=003)
    **)Then it will query the parent department in eDirectory based on the attributes set in as described above.
    **)Then it will query the manager within this parent department in eDirectory based on the attributes set in as described above.
    **)And finally it will set this managers role DN to the manager attribute of the current OR
    *)If not it will query for the department for this member. (RSIGN=A, SCLAS=O, RELAT=003)
    **)Then it will query for the manager in this department in eDirectory based on the attributes set in as described above.

  • The fourth template (“set-roles-directReports-attr”) set the direct reports on the current object.

    This template is pretty much the same. The big differences are handling multiple values (a manager has more that one direct reports) and the fact that any manager can have directReports in the child departments.

    First we check if the current object is a manager. (RELAT=012)
    *)If so it will query for the department for this manager. (RSIGN=A, SCLAS=O, RELAT=003)
    **)Then it will query the child departments in eDirectory based on the attributes set in as described above.
    **)Then it will query the managers within these child departments in eDirectory based on the attributes set in as described above.
    **)Finally, it will set this role DN to the directReports attribute of the current Organizational.
    *)AND
    **)It will query for the members in this department in eDirectory based on the attributes set in as described above.

There is an important thing to worry about:

If there is a SOBID in the result, it will find the objectDN with a query to eDirectory. If this query is empty the given object is NOT there yet,

So we have to make sure that with each new organizational role the manager attributes on the directReports are set and the directReport attribute on the manager object is set.

For this there are two additional templates.

		<xsl:if test="ancestor-or-self::add[@class-name='Organizational Role']">
			<xsl:call-template name="set-roles-managers-directReports"/>
			<xsl:call-template name="set-roles-directReports-manager"/>
		</xsl:if>

I will not go into these, by now you’ll know enough on these queries to handle everything.

You can find the Publisher Command OrgChart Transform Stylesheet, and the modified Publisher Command Transform Stylesheet in the attachments.

Please also review the articles from Geoffrey Carmen on this (coming soon) and also review the articles by Martyn Durrant on this issue regarding PFAL, Change pointers and historic data.

Good luck with it.

1 vote, average: 5.00 out of 51 vote, average: 5.00 out of 51 vote, average: 5.00 out of 51 vote, average: 5.00 out of 51 vote, average: 5.00 out of 5 (1 votes, average: 5.00 out of 5)
You need to be a registered member to rate this post.
Loading ... Loading ...

Categories: Uncategorized

Disclaimer: This content is not supported by Novell. It was contributed by a community member and is published "as is." It seems to have worked for at least one person, and might work for you. But please be sure to test it thoroughly before using it in a production environment.

Comment

RSS