in this Blog I would like to describe how distinct business object which refer to each other can be replicated from two different business systems to SAP C4C without losing their relation.
This will be done by adjusting the key mapping in a custom Partner Development Integration (SAP Cloud Application Studio) implementation .
Problem description
In two external systems A and B we have two entities X and Y. Entity X has a relation to entity Y. If now entity X is replicated from system A to C4C and entity Y is replicated from system B to C4C, then the relation of entity X to entity Y gets lost.
The reason is that the key mapping for the replication of entity Y only refers to Business system B and not system A.
An example is the new Master Data Integration (MDI) for business partners as central hub for master data distribution:
In this integrated scenario business partner data which were created in S/4 are replicated to SAP Sales Cloud via Master Data Integration. On the other hand data for sales organizations from S/4 are replicated directly to SAP Sales Cloud
The business partner with reference to the sales organization coming from MDI are now not mapped to the right sales organization because the MDI as a business system is not related to sales organizations in the key mapping.
To solve this, we need to tell SAP Sales Cloud that Master Data Integration is actually using the keys to identify sales organizations which came from S4 and therefore different business system.
A further scenario is, where two external business systems “A” and “B” are replicating the same business object instances to SAP Sales Cloud using the same external IDs.
Since they are coming from different business systems SAP Sales Cloud does not know they belong to the same object. By default SAP Sales Cloud will create two different business object instances for these having different local Cloud for Customer Keys/IDs.
This is a common use case for business partners if a business system change is intended after a migration.
Desired behavior shall be to create one business object instance only from “A” and to update this instance with data from the other system “B”.
To solve this, we again need to duplicate the key mapping entries for this business object from “A” to “B”
Solution
To solve this, I created the following snippet of code.
This code copies Key/ID mappings of a given ID scheme code (e.g. sales organization keys) created for one business system “A” to be also used for the second business system “B”.
Please note the following restriction:
This code copies Key/ID mappings as they are written to the data base upon creation or change.
Already existing key mappings will not be considered as long as they are not modified in any way.
Therefore please deploy and test this code before you consider to set up such a scenario.
Steps to be performed:
So here is how it is done:
Using the SAP Cloud Application Studio, please extend the following Business Object:
Name: ObjectIdentifierMapping NameSpace: http://sap.com/xi/CommunicationServicesManagement/Global
Create the Script File for the “BeforeSave” event of the root node with the “mass enabled” flag set.
Node: Root Event: "BeforeSave" Mass Enabled: checked
Paste the code at the end of this blog into the ObjectIdentifierMapping-Root-Event-BeforeSave.absl.
Then you must adjust the code as follows to cater for your needs:
-
- Check and adjust the RemoteIdentifierDefiningSchemeCode you want to duplicate to determine the ID scheme codes relevant for your use case (Line 14, 15).
A list of scheme codes can be found in the SAP Cloud Application Studio Repository Explorer.
Check the following DataType vor valid values: IdentifierDefiningSchemeCode.
I added support for multiple ID scheme codes which complicates the code a bit since this requires a loop for each scheme code as well as filtering to ensure processing of the correct code per iteration.
- Check and adjust the RemoteIdentifierDefiningSchemeCode you want to duplicate to determine the ID scheme codes relevant for your use case (Line 14, 15).
-
- Adjust the source and target business system IDs hard-coded into the ABSL script code you want to copy the ID mappings from/to.
I have added a check to distinguish between production and development systems.
But this could also be done to check whether development systems are existing and if not, fall back to the other since you are most likely in production then.
- Adjust the source and target business system IDs hard-coded into the ABSL script code you want to copy the ID mappings from/to.
ABAP Script language (ABSL) Code
for SAP Cloud Application Studio
/*
SAP Business ByDesign scripting language implementation for:
Business Object: ObjectIdentifierMapping
Node: Root
Event: BeforeSave
*/
import ABSL;
import AP.Common.GDT;
import DocumentServices.Global;
import CommunicationServicesManagement.Global;
// pre-filter on ID type
var relevantIDMappings = this.Where(
n => n.RemoteIdentifierDefiningSchemeCode == "20" // ERP Materials
|| n.RemoteIdentifierDefiningSchemeCode == "27"); // ERP Plants
if (relevantIDMappings.Count() == 0) {
return; // fast exit: no relevant ID type
}
// determine business systems involved
var sourceBusinessSystemID : CommunicationSystemParticipatingBusinessSystemID;
var targetBusinessSystemID : CommunicationSystemParticipatingBusinessSystemID;
if (Context.IsProductionTenant()) {
sourceBusinessSystemID.content = "PW9CLNT100"; // adjust these business system IDs
targetBusinessSystemID.content = "PW9CLNT300"; // to fit your specific environment
} else {
sourceBusinessSystemID.content = "QW9CLNT100"; //
targetBusinessSystemID.content = "QW9CLNT300"; //
}
var sourceBusinessSystem = CommunicationSystem.ParticipatingBusinessSystem.Retrieve(sourceBusinessSystemID);
var targetBusinessSystem = CommunicationSystem.ParticipatingBusinessSystem.Retrieve(targetBusinessSystemID);
if (!sourceBusinessSystem.IsSet() && !targetBusinessSystem.IsSet()) {
// either source or target BusinessSystem ID is incorrect
return;
}
// filter on source business system
relevantIDMappings = relevantIDMappings.Where(n => n.RemoteBusinessSystemUUID.content == sourceBusinessSystem.UUID.content);
if (relevantIDMappings.Count() == 0) {
return; // another fast exit: no ID mapping for the relevant business systems
}
// copy once per ID scheme type
foreach (var IDtype in relevantIDMappings.DistinctBy(n => n.RemoteIdentifierDefiningSchemeCode)) {
// restrict mapings relevant based on current ID scheme type
var sourceIDMappings = relevantIDMappings.Where(n => n.RemoteIdentifierDefiningSchemeCode == IDtype.RemoteIdentifierDefiningSchemeCode);
// query for existing target mappings
var targetIDMappingQuery = ObjectIdentifierMapping.QueryByElements;
var targetIDMappingQueryParams = targetIDMappingQuery.CreateSelectionParams();
targetIDMappingQueryParams.Add(targetIDMappingQuery.RemoteBusinessSystemUUID.content, "I", "EQ", targetBusinessSystem.UUID.content);
targetIDMappingQueryParams.Add(targetIDMappingQuery.RemoteIdentifierDefiningSchemeCode, "I", "EQ", IDtype.RemoteIdentifierDefiningSchemeCode);
foreach (var sourceIDMapping in sourceIDMappings) {
targetIDMappingQueryParams.Add(targetIDMappingQuery.LocalObjectNodeReference.UUID.content, "I", "EQ", sourceIDMapping.LocalObjectNodeReference.UUID.content);
}
var targetIDMappings = targetIDMappingQuery.Execute(targetIDMappingQueryParams);
// process mappings
foreach (var sourceIDmapping in sourceIDMappings) {
// check target mapping existence
var targetIDMapping = targetIDMappings.Where(n => n.LocalObjectNodeReference.UUID.content == sourceIDmapping.LocalObjectNodeReference.UUID.content);
var count = targetIDMapping.Count();
if (count == 0) {
// create id mapping
var newIDMapping = ObjectIdentifierMapping.Create();
newIDMapping.LocalObjectNodeReference.ObjectID.content = sourceIDmapping.LocalObjectNodeReference.ObjectID.content;
newIDMapping.LocalObjectNodeReference.ObjectNodeTypeCode.content= sourceIDmapping.LocalObjectNodeReference.ObjectNodeTypeCode.content;
newIDMapping.LocalObjectNodeReference.ObjectTypeCode.content = sourceIDmapping.LocalObjectNodeReference.ObjectTypeCode.content;
newIDMapping.LocalObjectNodeReference.UUID.content = sourceIDmapping.LocalObjectNodeReference.UUID.content;
newIDMapping.RemoteBusinessSystemUUID.content = targetBusinessSystem.UUID.content;
newIDMapping.RemoteIdentifierDefiningSchemeCode = sourceIDmapping.RemoteIdentifierDefiningSchemeCode;
newIDMapping.RemoteObjectID.content = sourceIDmapping.RemoteObjectID.content;
newIDMapping.OriginTypeCode = sourceIDmapping.OriginTypeCode;
} else if (count == 1) {
// update id mapping
targetIDMapping.GetFirst().RemoteObjectID.content = sourceIDmapping.RemoteObjectID.content; }
}
}