Skip to Content

C4C Application Enhancements: Building a Change Log for Business Partners

Note of the 31st July 2015:

the following solution has been thought and realized for the Release 1411 and carried on until Release 1505.

SAP Cloud for Customer Release 1508 delivered a Standard Solution for the Business Partner Change Log, available by simply enabling the CHANGES tab in your user/role layout and playing with it, as shown in the picture below:

changes tab.png

From a personal point of view, the article content has been anyway an interesting and challenging achievement that let us figure out anyway how to deliver a complex enhancement on the standard C4C solution. Consequently, the lessons learnt have been helpful for few of other Client’s requirements we are achieving by enhancements.

Thank you all for having appreciated the content of the article during the last months.

All the best wishes,

Davide


SAP Cloud for Customer is the new Customer-Centric Enterprise Cloud solution designed and released by SAP for the Customer Engagement and Relationship Management. This new solution enables you to align the business organizations and units around the Customer, with Marketing, Sales and Customer Service functionalities at the front line to the Customer.

In the new SDK Framework provided with SAP C4C (called SAP Cloud Application Studio) the main advantage is the model of Designing and Programming based on Business Objects. Every business entity, such as Master Data entities, can be seen as an instance of a specific class: the Business Object, with inside all the contained data and fields seen as a member properties, and with all the actions seen as class methods. The picture below shows the architecture of the BusinessPartnerBusiness Object:

/wp-content/uploads/2014/12/image001_600938.png

As you can see, all the properties defined in the BusinessPartner BO definition map the fields and the tables which are present in the Customer Account WorkCenter View, where Users can check and change any information on their managed Customers and Prospects, as shown in the picture below:

/wp-content/uploads/2014/12/image004_600848.png

The advantage of this programming model is that the designer is not just free to use the given actions programmatically in the code, but even to define and extend the BO with new fields, new referenced child BO and new actions.

In this article we focus on an Implementation and Realization of an Extension on the Account functionality. Consider for instance the case that a User in the Company’s Sales Department needs to keep track of the full maintenance and management of the information stored for the Customers in his portfolio. Sometimes, in our past CRM Project experiences, our User asked if was possible to track the changes done in the system for some relevant information such as the Company name, the address and the contact phone. In a way to track the changed field, the value, the time of the change and even the User who did the change on the system.

Using the SAP CRM system, this result would have been achieved by enabling the Change History Assignment Block on the Account UI Page for the required User(s). Nevertheless, in SAP Cloud for Customer Rel. 1411 a functionality similar to the Change Log is still missing in the Account WorkCenter, and in order to achieve a similar User requirement we should define a custom enhancement that keeps tracks of the changes on relevant Account information.

In order to define our scope and purposes, we can summarize the desired requirements in the following numbered list:

RQ01.    Supervisors MUST have the ability to flag a BP record as “Monitored Customer” and add a “Review Date” and then capture changes in the change log if the flag is set;

RQ02.    The fields created in RQ01 need to only be available to a user of a specific business role (Supervisor);

RQ03.    The tracked changes must be displayed in a Change log, strictly available just for a few set of roles.

The following sections will explain the solution developed in order to achieve that result.

Solution

The solution has been realized using the SAP Cloud Application Studio. The core of the solution is based on an enhancement on the BusinessPartner Business Object, made by adding a custom behaviour on the BeforeSave Event. In details, the list of the enhancements on the core logic is the following:

·        Define a new Business Object, which will collect all the changes done on each relevant field (such as the Name, the Address, the Phone and the Email) with the old value, the new value, the user who did the change and the time it has been done;

·        Enhance the BusinessPartner Business Object by adding a new checkbox field (called “Monitored Customer”);

·        Enhance the BusinessPartner Business Object by adding a new BeforeSave Event Handler with the following logic: if the Monitored Customer flag has been checked, then create a new entry for the Change Log;

·        Create a new UI screen that will collect all the Change Log entries, making them available for part of the Business Roles defined in the Cloud for Customer implementation.

The sections below will illustrate each of the components in details.

Business Object definition

The data modelling which will provide the Change Log functionality could be easily designed and built by defining a new Business Object (AccountChangeLogEntry), which will represent one of the log entries. The BO code is shown below:

import AP.Common.GDT as apCommonGDT;

import AP.FO.BusinessPartner.Global;

importAP.PC.IdentityManagement.Global;

[DeploymentUnit(Foundation)] businessobject AccountChangeLogEntry {

      [Label (“Change Log Entry ID”)]  element ChangeLogEntryID:ID;

      [Label (“Change Type”)]          element ChangeType:ChangeTypeCode;

      [Label (“Field Name”)]            element FieldName:LANGUAGEINDEPENDENT_MEDIUM_Name;

      [Label (“Old Value”)]            element OldValue:LANGUAGEINDEPENDENT_EXTENDED_Text;

      [Label (“New Value”)]            element NewValue:LANGUAGEINDEPENDENT_EXTENDED_Text;

      [Label (“Changed At”)]            element ChangedAt:Time;

      [Label (“Changed On”)]            element ChangedOn:Date;

      [Label (“Timestamp”)]            elementChangedAtTimestamp:GLOBAL_DateTime;

      [Label (“Active”)]                elementActive:Indicator;

      [Label (“Account ID”)]            element AccountID:BusinessPartnerID;

      associationRefBusinessPartner   to BusinessPartner;

      [Label (“Identity UUID”)]         element IdentityUUID:UUID;

      associationRefUser               to Identity;

     

}

Important: if you want that the created Business Object will interact with the Business Partner BO, it is required that they both share the same Deployment Unit. Otherwise the BO content will be read-only for the Business Partner, and no new entries could be created!

Furthermore, in order to use the BO and look up the BO data in another block of code, it is necessary to define a custom Query on the AccountChangeLogEntry BO. The Query could be created by using the Create Query functionality in the BO Contextual Menu:

/wp-content/uploads/2014/12/image006_600851.png

And will be defined by the following parameterization:

/wp-content/uploads/2014/12/image007_600852.png

Business Partner BO extensions

The code for the BusinessPartner BO Extensions is displayed below:

import AP.Common.GDT;

import AP.FO.BusinessPartner.Global;

[Extension] businessobjectAP.FO.BusinessPartner.Global:BusinessPartner {

           

            node Common {

                    [Label (“Name Validation Flag”)] element flgNameValidation:Indicator;

                    [Label (“Monitored Customer”)] element flgMonitoredCustomer:Indicator;

                    [Label (“Review Date”)] elementreviewDate:Date;         

              }

}

In order to change the value for these fields, they has been put on the Header pane in the UI component COD_Account_TI, as shown below:

/wp-content/uploads/2014/12/image009_600860.png

The effect on the account screen is shown in the picture below:

/wp-content/uploads/2014/12/image012_600862.png

BeforeSave Event Handler Logic

The BeforeSave logic has been developed in a way that the initial value of a field is tracked with a new AccountChangeLogEntry BO, if the flag “Monitored Customer” has been enabled. Then, every time the BeforeSave Event Handler is called, the current value is compared with the latest value in the AccountLChangeLogEntry BOs list. If it is different, a new value is stored.

Important: if you are interested to track the value for the fields belonging to the BusinessPartner Common node, then you should put the following logic in the Common node Event-BeforeSave.absl script. Otherwise the code won’t ever be triggered!

The full implementation code (with comments for all the steps done) has been displayed below:

import ABSL;

import AP.Common.GDT;

// we start setting up all the required variables:

var bp = this.ToRoot.InternalID;

var oldLogEntry:BusinessObject::AccountChangeLogEntry;

var logEntry:BusinessObject::AccountChangeLogEntry;

var oldValue:LANGUAGEINDEPENDENT_EXTENDED_Text;

var newValue:LANGUAGEINDEPENDENT_EXTENDED_Text;

var typeCode:ChangeTypeCode;

var fieldName= “”;

// The logic has been restricted for those Accounts who have the flag “Monitored Customer” enabled:

if (this.flgMonitoredCustomer == true) {

// we extract the list of field to monitor from the BCO MONITORED_FIELDS:

var fieldList= MONITORED_FIELDS.QueryByElements.Execute();

var count = MONITORED_FIELDS.QueryByElements.Count();

foreach (varfield in fieldList) {

fieldName = field.FIELD_NAME;

// For each of them, the new value should be found in a particular position in the Business Object structure:

switch (fieldName) {

      case (FieldListCode.CO_ORG_NAME) {

              newValue= this.Organisation.Name.FirstLineName+ ” “ + this.Organisation.Name.SecondLineName;

              typeCode= ChangeTypeCode.CO_NAME;

      }

      case (FieldListCode.CO_GIVEN_NAME) {

              newValue= this.Person.Name.GivenName;

              typeCode= ChangeTypeCode.CO_NAME;

      }

      case (FieldListCode.CO_FAMILY_NAME) {

              newValue= this.Person.Name.FamilyName;

              typeCode= ChangeTypeCode.CO_NAME;

      }

}

// at first we query the existing ChangeLog entries for that BP and field:

var query = AccountChangeLogEntry.QueryLastEntry.QueryByElements;

var resultData= query.ExecuteDataOnly();

var selectionParams= query.CreateSelectionParams();

selectionParams.Add(query.RefBusinessPartner_InternalID, “I”, “EQ”, bp);

selectionParams.Add(query.FieldName, “I”, “EQ”, fieldName);

resultData = query.ExecuteDataOnly(selectionParams);

// The processing of which line add to the table will depend on which are the existing results:

if (resultData.Count() == 0) {

      // In this case, this is the first monitored entry for the BP/Field.

      // The old value has been thus set to empty:

      if (!newValue.IsInitial()) {

              logEntry= AccountChangeLogEntry.Create(

                    ChangeLogReuseLibrary.CreateNewEntry(typeCode, fieldName, “”, newValue, bp, true));

              logEntry.RefBusinessPartner = this.ToRoot;

      }

} else {

      //In this case, we get the old value by the most recent entry in the table:

      resultData.OrderByDescending(n=>n.ChangedAtTimestamp);

      oldValue= resultData.GetLast().NewValue;

     

      if (oldValue != newValue) {

      //just in case that the extracted vaue is different than the current value, then add a new line:

            logEntry = AccountChangeLogEntry.Create(

                    ChangeLogReuseLibrary.CreateNewEntry(typeCode, fieldName, oldValue,  newValue, bp, true));

              logEntry.RefBusinessPartner = this.ToRoot;

      }

}

}

}

After encapsulating the core logic in an external Reuse Library (see the section below) the Event Handler logic has been converted in a simpler implementation, which is displayed below:

·        For the Common node BeforeSave Event Handler:

import ABSL;

ChangeLogReuseLibrary.ChangeLogController(this.ToRoot.InternalID, ChangeTypeCode.CO_NAME);

·        For the AddressInformation node BeforeSave Event Handler:

import ABSL;

ChangeLogReuseLibrary.ChangeLogController(this.ToRoot.InternalID, ChangeTypeCode.CO_ADDRESS);

·        For the Identification node BeforeSave Event Handler:

import ABSL;

ChangeLogReuseLibrary.ChangeLogController(this.ToRoot.InternalID, ChangeTypeCode.CO_ID);

ChangeLog Reuse Library

Some common procedures:

·        The creation of a new Change Log Entry;

·        The generation of a new number (given a number range);

·        The core logic of looking-up the old field value, comparing with the new value and adding a new Entry in the Change Log

have been encapsulated in a Reuse Library called ChangeLogReuseLibrary. The listings below will show you the code implemented for each of them.

Create New Entry Function

/wp-content/uploads/2014/12/image014_600865.png

import ABSL;

import AP.FO.BusinessPartner.Global;

var result: elementsof AccountChangeLogEntry;

result.ChangedAt= Context.GetCurrentSystemTime();

result.ChangedOn= Context.GetCurrentSystemDate();

result.ChangedAtTimestamp= Context.GetCurrentGlobalDateTime();

result.ChangeLogEntryID= ChangeLogReuseLibrary.GetNumber(AccountChangeLogEntryNumberRan.CO_LOG_ITEM);

result.ChangeType= ChangeType;

result.FieldName= FieldName;

result.OldValue= OldValue;

result.NewValue= NewValue;

result.Active= Active;

result.AccountID= RefBusinessPartner;

result.IdentityUUID= Context.GetCurrentIdentityUUID();

return result;

Get a new ID Number (by Number Range)

/wp-content/uploads/2014/12/image015_600866.png

import ABSL;

var result : DataType::ID;

var number = NumberRange.DrawNumber(NumberRangeCode);

switch (NumberRangeCode) {

      case (AccountChangeLogEntryNumberRan.CO_LOG_ITEM) { number= number + 1000000000; }

      case (AccountChangeLogEntryNumberRan.CO_OTHER) { number= number + 2000000000; }

}

result = number.ToString();

var stop_the_damn_debugger_here= true;

return result;

Change Log Controller and Comparing tool

/wp-content/uploads/2014/12/image016_600867.png

import ABSL;

import AP.Common.GDT;

import AP.FO.BusinessPartner.Global;

import AP.PC.IdentityManagement.Global;

// we start setting up all the required variables:

var bp = Parameter::BusinessPartnerID;

var bp2:BusinessPartnerID;

var em2:IdentityID;

var refBP:BusinessObject::BusinessPartner= BusinessPartner.Retrieve(bp);

var oldLogEntry:BusinessObject::AccountChangeLogEntry;

var logEntry:BusinessObject::AccountChangeLogEntry;

var oldValue:LANGUAGEINDEPENDENT_EXTENDED_Text;

var newValue:LANGUAGEINDEPENDENT_EXTENDED_Text;

var typeCode:ChangeTypeCode;

var fieldName= “”;

// The logic has been restricted for those Accounts who have the flag

// “Monitored Customer” enabled:

if (refBP.Common.GetFirst().flgMonitoredCustomer == true) {

var availableFieldsByTypeQuery= CHANGETYPE_FIELD_ASSOCIATION.QueryByElements;

var afbtqParams= availableFieldsByTypeQuery.CreateSelectionParams();

afbtqParams.Add(availableFieldsByTypeQuery.CHTYPE, “I”, “EQ”, ChangeTypeNode);

var avFieldList= availableFieldsByTypeQuery.Execute(afbtqParams);

var aCount = avFieldList.Count();

// we extract the list of field to monitor from the BCO MONITORED_FIELDS:

var fieldListQuery= MONITORED_FIELDS.QueryByElements;

var flParam = fieldListQuery.CreateSelectionParams();

if (aCount != 0) {

      foreach (var record in avFieldList) {

              flParam.Add(fieldListQuery.FIELD_NAME, “I”, “EQ”, record.FIELD);

      }

}

var fieldList= fieldListQuery.Execute(flParam);

var count = fieldList.Count();

foreach (varfield in fieldList) {

fieldName = field.FIELD_NAME;

// For each of them, the new value should be found in a particular position

// in the Business Object structure:

switch (fieldName) {

      case (FieldListCode.CO_ORG_NAME) {

              newValue      = refBP.Common.GetFirst().Organisation.Name.FirstLineName

                                  + ” “

                                  + refBP.Common.GetFirst().Organisation.Name.SecondLineName;

      }

      case (FieldListCode.CO_GIVEN_NAME) {

              newValue= refBP.Common.GetFirst().Person.Name.GivenName;

      }

      case (FieldListCode.CO_FAMILY_NAME) {

              newValue= refBP.Common.GetFirst().Person.Name.FamilyName;

      }

      case (FieldListCode.CO_PHONE) {

              newValue= refBP.CurrentDefaultAddressInformation.Address.DefaultConventionalPhone.FormattedNumberDescription;

      }

}

// at first we query the existing ChangeLog entries for that BP and field:

var query = AccountChangeLogEntry.QueryLastEntry.QueryByElements;

var resultData= query.ExecuteDataOnly();

var selectionParams= query.CreateSelectionParams();

selectionParams.Add(query.RefBusinessPartner_InternalID, “I”, “EQ”, bp);

selectionParams.Add(query.FieldName, “I”, “EQ”, fieldName);

resultData = query.ExecuteDataOnly(selectionParams);

// The processing of which line add to the table will depend on which are the existing

// results:

if (resultData.Count() == 0) {

      // In this case, this is the first monitored entry for the BP/Field.

      // The old value has been thus set to empty:

      if (!newValue.IsInitial()) {

              logEntry= AccountChangeLogEntry.Create(

                    ChangeLogReuseLibrary.CreateNewEntry(

                          ChangeTypeNode, fieldName, “”, newValue, bp, true));

              logEntry.RefBusinessPartner= refBP;

              logEntry.RefUser= Identity.Retrieve(logEntry.IdentityUUID);

              //logEntry.RefBusinessPartner = BusinessPartner.Retrieve(bp);

              bp2= logEntry.RefBusinessPartner.InternalID;

              em2= logEntry.RefUser.ID;

      }

} else {

      //In this case, we get the old value by the most recent entry in the table:

      resultData.OrderByDescending(n=>n.ChangedAtTimestamp);

      oldValue= resultData.GetLast().NewValue;

     

      if (oldValue != newValue) {

      //just in case that the extracted vaue is different than the current value,

      //then add a new line:

              logEntry= AccountChangeLogEntry.Create(

                    ChangeLogReuseLibrary.CreateNewEntry(

                          ChangeTypeNode, fieldName, oldValue,    newValue, bp, true));

              logEntry.RefBusinessPartner= refBP;

              logEntry.RefUser= Identity.Retrieve(logEntry.IdentityUUID);

              //logEntry.RefBusinessPartner = BusinessPartner.Retrieve(bp);

              bp2= logEntry.RefBusinessPartner.InternalID;

              em2= logEntry.RefUser.ID;

      }

}

}

}

Address management

In the SAP C4C Data Model, the Address is a different Business Object than the Business Partner, and the AddressInformation node for the Business Partner BO stores just the association between an Address (stored in its Master Data) and the Business Partner.

This means that in case the user updates the association stored in the AddressInformation node (ex: by adding a new Address or removing an existing one for the Account), then the AddressInformation node BeforeSave Event will be fired. In the case instead the user updates the data within an existing Address (ex: by replacing the Phone Number) the AddressInformation node BeforeSave Event won’t be fired.

We then defined a better way to handle eventual changes to the Address data by implementing an extension to the AddressSnapshot BO (defined in the namespace: AP.FO.Address.Global), on the nodes with relevant information fields:

·        Telephone;

·        FormattedAddress;

·        PostalAddress;

·        Email.

A custom BeforeSave Event Handler implementation has been provided for each of them. In addition, a custom association between the Address UUID and the Business Partner ID has been defined in the Cloud Data Model by defining a new custom Business Object, called BusinessPartner_Address_Check. The custom BO definition is displayed here below:

import AP.Common.GDT as apCommonGDT;

import AP.FO.BusinessPartner.Global;

[DeploymentUnit(Foundation)] businessobject BusinessPartner_Address_Check {

              elementBusinessPartnerID:BusinessPartnerID;

              elementAddressUUID:ID;

}

The logic has been defined as it follows:

1.    As soon that the Monitored Customer flag is set, the Common node BeforeSave Event Handler stores the association between the BP and the Address UUID in a new BusinessPartner_Address_Checkentry (if no previous entry existed);

2.    At the time the Address data (telephone number or street, for instance) have been changed within the same address, the BeforeSave event for the AddressSnapshot BO is fired. A custom Event Handler will:

a.    Check if the Address has been monitored (by executing a query the existing BusinessPartner_Address_Check BOs);

b.    In the case it has been, read the Business Partner data, check its Monitored Customer flag, and call the ChangeLogController Change Library function.

The following sections will show the changes to the code in order to provide the desired implementation.

BusinessPartner-Common BeforeSave Event Handler

The code for the Common node BeforeSave Event Handler implementation has been then changed to the following listing:

import ABSL;

// RQ01-RQ02: Call to the Core Logic: ADDRESS:

// The following logic will the address UUID against the Monitored BP,

// in a custom Business Object.

if (this.flgMonitoredCustomer == true) {

      var bpac:BusinessObject::BusinessPartner_Address_Check;

      var addressUUID = this.ToRoot.AddressSnapshot.UUID;

      var bp = this.ToRoot.InternalID;

      // at first the code checks that the address-bp relation has been registered

      // into the BO data:

      var query = BusinessPartner_Address_Check.QueryByElements;

      var params = query.CreateSelectionParams();

      params.Add(query.AddressUUID, “I”, “EQ”, addressUUID.content.ToString());

      params.Add(query.BusinessPartnerID, “I”, “EQ”, bp);

      var results = query.Execute(params);

      var count = results.Count();

      // the new record is submitted into the cloud only if no data is already there:

      if (count == 0) {

              bpac= BusinessPartner_Address_Check.Create();

              bpac.AddressUUID = addressUUID.content.ToString();

              bpac.BusinessPartnerID = bp;

      }

}

// RQ01-RQ02: Call to the Core Logic: NAME:

ChangeLogReuseLibrary.ChangeLogController(this.ToRoot.InternalID, ChangeTypeCode.CO_NAME);

AddressSnapshot BeforeSave Event Handler

The following code has been implemented for the BeforeSave EventHandler for the following nodes:

·        Telephone;

·        FormattedAddress;

·        PostalAddress;

·        Email.

import ABSL;

import AP.Common.GDT;

import AP.FO.BusinessPartner.Global;

var bpac:BusinessObject::BusinessPartner_Address_Check;

var addressUUID= this.ToParent.UUID;

var bp:BusinessPartnerID;

// for each address, the code checks the related bp in the Adress-BP Business Object data:

var query = BusinessPartner_Address_Check.QueryByElements;

var params = query.CreateSelectionParams();

params.Add(query.AddressUUID, “I”, “EQ”, addressUUID.content.ToString());

var results = query.Execute(params);

var count = results.Count();

// address could potentially have been shared among contacts.

// then update the log for everyone:

foreach (varrecord in results) {

      if (!record.BusinessPartnerID.IsInitial())

              ChangeLogReuseLibrary.ChangeLogController(

                    record.BusinessPartnerID,

                    ChangeTypeCode.CO_ADDRESS);

}


User Interface additional tools

This section will deal with some additional tools we can realize on the Cloud for Customer User Interface, in order to let it be suitable for Administrators and Customer Managers.

In the solution we realized the following UI tools:

·        A global ACCOUNT CHANGE LOG UI WorkCenter, that will show all the tracked changes for all the Account defined in the system (with a query to the Business Object AccountChangeLogEntry);

·        A local CHANGE LOG, that will show all the tracked changes for the single Account, and which has been attached as a new Tab to the Account/Customer WorkCenter.

The following sections will describe the single UI Tools.

Global ACCOUNT CHANGE LOG WorkCenter

For the Account Change Log WorkCenter, the following steps have been followed:

1.    Select Create Screens from the Business Object Contextual menu, as shown below:

/wp-content/uploads/2014/12/image017_600882.png

2.    Select the options below, specifying a Short ID:

/wp-content/uploads/2014/12/image018_600899.png

The environment will automatically define the following UI Screens:

/wp-content/uploads/2014/12/image019_600905.png

3.    In particular, we chose the Object Work List item (the AccountChangeLog_OWL.OWL.uicomponent screen), because it was the one that could better resemble the Log Layout, and defined the following additional functionalities inside:

·        Refresh button: done by Firing an Event Handler that execute again the Default Set for the Default Query, as shown below:

/wp-content/uploads/2014/12/image020_600906.png


·        Delete button: done by adding LayoutStackPanel item on every line, which content is a Delete button:

/wp-content/uploads/2014/12/image021_600907.png


The button will fire the Event Handler defined below:

/wp-content/uploads/2014/12/image022_600908.png

·        Thing-Type Navigation to the Account: define the InternalID field proprieties as shown below:

/wp-content/uploads/2014/12/image024_600909.png

And then, on the Data Model tab select the UUID field. The DataField proprieties should be set up as shown below:

/wp-content/uploads/2014/12/image026_600911.png

4.    After these changes, activate and save the screen. After allowing your user to the New WorkCenter Frame, you will be able to see the new ACCOUNT CHANGE LOG functionality.

Embed the Change Log as a Tab on Customer Workcenter

In order to show the data at the Account TI screen level (as a new tab) the following activities have been done:

1.    Add a new Embedded Component (EC) to the Solution, and filling it with a table made by the fields provided by the QueryByBP query:

/wp-content/uploads/2014/12/image030_600912.png

       

2.    Define a new Inport for getting the Account ID from the main application:

/wp-content/uploads/2014/12/image032_600913.png

3.    Define a new UI Query that runs the QueryByBP and put the result in the DataList Data Model node:

/wp-content/uploads/2014/12/image033_600917.png

4.    Define a new Event Handler (and put on the OnFire properties of the Inport), that copies the input parameter to the query parameter and runs the Query:

/wp-content/uploads/2014/12/image034_600918.png

5.    Save and Activate everything.

6.    Open a new extension of the UI Screen COD_Account_TI, and in the Extensibility Explorer, add the generated EC, with the binding specified below:

/wp-content/uploads/2014/12/image035_600919.png

/wp-content/uploads/2014/12/image036_600920.png

7.    Save and Activate the TI.

Business Roles Restrictions

In order to achieve the RQ02 Requirement, we can use the configuration of a custom Page Layout, assigning it then to few of the Business Roles available. The steps are explained below:

1.    From the UI5 interface, select the menu voice Adapt New Page Layout:

/wp-content/uploads/2014/12/image037_600921.png

2.    After creating the new Layout, deselect the option “Visible” from both the CHANGE LOG tab and the Monitored Customer field;

3.    Select the menu voice Adapt Assign Page Layout, and modify the options in the list as shown below:

/wp-content/uploads/2014/12/image038_600922.png

4.    Save and logon with the Sales Representative to check the result.


Final result

The final result has been shown in the pictures below.

The Change Log has been displayed as a Tab into the Account TI UI Screen, with all the tracked changes inside, sorted by hour and date of change:

/wp-content/uploads/2014/12/image040_600923.png


Furthermore, the ACCOUNT CHANGE LOG WorkCenter (containing all the tracked changes from all the monitored Accounts in the system) gave us the result below:

/wp-content/uploads/2014/12/image042_600924.png

About the Author

/wp-content/uploads/2014/12/image044_600925.jpg I am Davide De Luca, and at present time I work as a Senior Consultant at Bluefin Solutions Ltd for Manufacturing Business Process, coming from several work experience as IT Specialist and SAP CRM Consultant in Capgemini, E-Utile – an ATOS WorldGrid Company and in Accenture (Rome office).

I can offer a consistent experience on System Integration oriented on the Engineering of new and innovative services and solution for small/medium and big Enterprises based on SAP Product and Services. My experience in this market is such of 8 years.

In details, I have been reaching gradually the following skills:

·        Project design and deployment of enterprise resource planning services and software’s (based on SAP solutions);

·        Business Implementation, Configuration, Tuning and Technical Design of IT Solutions based on SAP Cloud for Customer (C4C) landscapes and scenarios;

·        Technical design and customizing of IT solutions based on system SAP CRM landscapes and scenarios;

·        Project design and deployment of new services and application for business purposes for SAP NetWeaver enterprise portal solutions.

More information about Bluefin Solutions at: http://www.bluefinsolutions.com/

44 Comments
You must be Logged on to comment or reply to a post.
    • Thank you Mithun.

      Yes, it has been strange when we discovered that no Change Log functionalities have been released in the standard C4C implementation. That’s the reason why we developed.

      Hope that the code snippets could be useful.

      Cheers,

      Davide

      • Hello Davide,

        There is already a possibility to get a history of changes.

        But this works only for Custom BOs and only in ByD systems, not in C4C. (Reason: different role codes of the tenants for ByD and C4C).

        I am sad to say that we do not offer the possibilty to switch it on for SAP BOs.

        Bye,

            Horst

        • Hi Horst,

          yes I had a discussion with some colleague of mine that is currently working on ByD, and then we did the activities explained in this article as an outcome of the replies we got on the following thread:

          Tracking the old field value in Business Objects Event Handler

          Unfortunately it seems that on the C4C front there isn’t so much on these features. We hope that now, after we deployed this solution, some of the SAP Development team consider the opportunity to review this code and implement a standard functionality.

          Cheers,

          Davide

          • Hello Davide,

            Good news:

            I am currently working on getting the good-old-ByDesign ChangeLog into the BODL code.

            You will be able to define per node / element which should be part of the ChangeLog.

            Plus: This would work for both ByDesign and Cloud4Customer. 😆

            Expected arrival: Release 1508

            Bye,

               Horst

          • Hi Horst,

            that’s a good news!

            In my opinion, the Account Change Log development honestly has been a good exercise for getting the grip and the taste of the Cloud Application Studio, but it has some limitations, due to the complexity required for looking up some fields and the maintainance required.

            I would be pretty happy to know if this experience has been useful for the standard ChangeLog development, lol…

            Kind regards,

            Davide

          • Hello Davide,

            Sorry, but I am just enabling the old stuff. 😕

            Currently there is nobody developing / enhancing / refurbishing the standard Change Log 🙁

            Bye,

                Horst

          • Hello Davide,

            I even did not find the section for the Cloud Application Studio in the link to “C4C 1508 Release Notes”. 🙁

            But it will come. 🙂

            I saw it in the SAP Cloud Application Studio 1508 delta feature rollout session.

            (They took my example for the demo 😀 )

            Bye,

               Horst

        • Hello Horst,

          As you have mentioned above that there is a possibility to get a history of changes for Custom BOs. Is this available via sdk for partner developed BOs so that we can view the change log via the CHANGES tab ?

          Is there any documentation on the same?

          Regards,

          Sangeeta

          • Hello Sangeeta,

            Yes, that’s possible. 😀

            Just annotate the elements / nodes you want to be tracked in the Change Log with [ChangeHistory].

            Afterwards follow the steps described in the docu at “Developer Desktop” -> “Business Objects” -> “Task” -> “Enable Change History”, but omit the BCO stuff.

            It seems that the Task section needs an update. 😕

            Bye,

               Horst

    • Hello Sriram,

      sorry if I reply just now, but I’m back from Christmas holidays from today.

      Well, the answer is the same as for the Premise SAP CRM solution: Business Roles are assigned to a Business User (with logon information), and the Business User has the reference to an Employee ID. If you need any further detail, I would suggest to take a look on the Cloud for Customer Administration Guide: https://websmp204.sap-ag.de/~sapidb/012002523100016725002014E/EN-2.pdf

      In the particular case of the Cloud Application Studio, the BO representing Business Users is called Identity (namespace: AP.PC.IdentityManagement.Global). In the example above, it is one of the fields of theCustom BO AccountChangeLogEntry.

      Hope I replied to your question. Please let me know if you need any other information.

      Cheers,

      Davide

      • Hi Davide,

        Thanks for your reply. I would like to know how Employee Bo and Identity Bo are related. In the Cloud Studio i did a Query By Identification on Employee Bo it showed me associations but i cant find Identity,

        One more question is how can i create a Query on extension Bo?

        Thanks in Advance

        Sriram

        • Hi Sriram,

          in the Employee BO you can use the node AssignedIdentity, which will contain the ID attribute (it’s the IdentityID), in case you are interested in retrieving the Identity from the Employee, or a QueryByElements, in the converse case you are interested in retrieving the Employee from an available ID.

          Please let us know if that hint fulfills your needs.

          Cheers,

          Davide

          • Hi Davide,

            One more query. I want to expose a webservice that can be used to fetch all Reporting Line Units.

            Since RLU BO dont have any query, i can create only a Read webservice which takes in an ID or UUID and gives me the RLU details.

            Is there a possibility that i can create a query on RLU BO so that i can expose it as webservice?

            Thanks in Advance

            Sriram

          • hi Sriram,

            you should create a custom Query component on your BO, and then create a WebService with the Query operation linked to the custom Query component.

            Please, let me know if it worked then.

            Cheers,

            Davide

  • One help from you all.

    My scenario is to assign the value for standard field in Opportunity–>Product tab. (say like amount) from Cloud Application Studio.

    I have checked with the Extensibility browser of Opportunity, but it just allows to adjust the properties of field like, Visibility / Mandatory check / Read only check only. And in script also those fields are locked (read only mode)

    Is this possible to set value for standard field through SDK? If so kindly help me out.

    Regards

    Swadini Sujanaranjan

  • Hi all,

    Thanks for your reply.

    I have added new fields on extending the bo and achieved it.

    But here my requirement is to set the value of ‘ExpectedNetAmount’ field which is in standard BO (Opportunity.Item.ExpectedNetAmount). For that, I tried to do something with Extensibility explorer it just allowing me to adjust properties as I said early.

    From SDK when I try to set value for any standard bo field, its in read only.

    I dono whether I could set the value for standard field through SDK or not.

    Kinldy help me.

    Regards

    Swadini Sujanaranjan

    • Hi Swadini,

      just a question: which is the deployment unit you used for the solution?

      I noticed that Read-Only fields in standard BO can happen in case there is a mismatch in the Deployment Unit of both (the Solution one and the BO one). They should be both set on CustomerRelationshipManagement.

      If this rule has been applied, then I can access to the Item Amount via the following:

      var amount = 58.60;

      this.Item.Create().ExpectedNetAmount.content = amount;

      Please let me know if it works for you.

      Cheers,

      Davide

      • Hi Davide

        Both my custom bo and standard Opportunity has the same deployment unit CustomerRelationshipManagement.

        One more clarification, how can we get the standard field using ‘this’ keyword. I m trying with Opportunity.Item.ExpectedNetAmount.contect = amount;

        Create() is not supported there.

        Please clear my point.

        Regards

        Swadini

          • Hi Swadini,

            no worries. In the meanwhile I was trying a mock up of your problem.

            At first I set up a new BO like this:

            import AP.Common.GDT as apCommonGDT;

            businessobject BusinessObject1 {

            element OpportunityID:BusinessTransactionDocumentID;
            element CustomAmount:Amount;
            action WriteAmount;

            }

            And then after I set up the action WriteAmount with the following logic:

            import ABSL;
            import AP.Common.GDT;
            import AP.CRM.Global;

            var opportunity:BusinessObject::Opportunity;

            opportunity = Opportunity.Retrieve(this.OpportunityID);

            opportunity.Item.GetFirst().ExpectedNetAmount.content = this.CustomAmount.content;

            This works in my case.
            Probably it’s just a matter of copying the content propriety in a content propriety.

            Glad to be helpful.

            Cheers,

            Davide

          • Hi Davide


            In Event Before save of Item node, I have written the below code:


            var amt = “23.00”;

            var cur = “USD”;

            var expam = this.ExpectedNetAmount.content;

            this.ExpectedNetAmount.Clear();

            this.ExpectedNetAmount.content = amt;

            this.ExpectedNetAmount.currencyCode = cur;


            In debugger its changing but in UI the previous value only resist. What can I do for this. Is there something like commit or save in code?

            Regards

            Swadini S

  • Hi Davide,


    Can you explain,in above before save event-handler,how to create BCO(MONITORED_FIELDS) its list of fields and BCS(Business Configuration Set) and What is field.FIELD_NAME.



    regards,

    Abhishek Kumar.

    • Hi Abishek,

      you are right. Honestly I thought I had specified that section in the main article, but I have checked that is actually missing. Thank you for noticing.

      The BCO MONITORED_FIELDS has been created just as a Customizing table with a couple of fields: FIELD_NAME and ENABLED, as shown here below:

      MONITORED_FIELDS.png

      The FIELD_NAME field has been created using an external Codelist, in a way I can have an extensible Drop-Down ListBox:

      /wp-content/uploads/2015/06/codelist_730108.png

      The list of Values and Descriptions in the Codelist is totally arbitrary. You can use your favourite values. After building and activating the BCO, the initial Configuration Set has been built has shown here below:

      FIELDS_SET.png

      Of course, you can then generate a Business Configuration View too and publish it into the Implementation Project WorkCenter of your C4C system, as explained in the Cloud Application Studio user manual.

      Please let me know if you need any other information about it.

      Cheers,

      Davide

  • Hi Davide,


    Thanks for your valuable help.Thank you very much.


    But I facing some issues once again  in before save event-handler code,In 1505 releases

    ChangeTypeCode not exist in the system in  var typeCode:ChangeTypeCode;

    And cannot access QueryLastEntry in

    var query = AccountChangeLogEntry.QueryLastEntry.QueryByElements; with mentioned namespaces.

    Also,how to access RefBusinessPartner_InternalID and bp in

    selectionParams.Add(query.RefBusinessPartner_InternalID, “I”, “EQ”, bp);

       






    regards,

    Abhishek Kumar.

    • Hi Abhishek,

      the ChangeType object is a custom Codelist, useful for bringing always the same constant values and to buind a quick Dropdown ListBox:


      ChangeType.png

      About the QueryLastEntry, it’s just a custom query. You can create it directly by rightclicking on the BO in the Solution Explorer, or you can maybe use the standard QueryByElements query.

      Kind regards,

      Davide

  • Hi Davide,


    Thanks once again.

    I cannot  access ChangeLogReuseLibrary in

    logEntry= AccountChangeLogEntry.Create(

                         ChangeLogReuseLibrary.CreateNewEntry(typeCode, fieldName, “”, newValue, bp, true));

    how to access it, it is custom or standard.

    Kind regards,

    Abhishek Kumar.

  • Hi Davide,



    Please help me to achieve the above task,how to access 

    ChangeLogReuseLibrary in

    logEntry= AccountChangeLogEntry.Create(

                         ChangeLogReuseLibrary.CreateNewEntry(typeCode, fieldName, “”, newValue, bp, true));

    how to access it, it is custom or standard.

    regards,

    Abhishek Kumar.


    • Hello Ajith,

      Solutions are “sandboxed”. They can only access entities from SAP and from their own solution.

      This is also true for BC Sets. 😛

      Sorry,

         Horst

    • Thank you, Nikhil.

      But I must say that, with the Release 1508, the functionality is now available on the Standard Solution. Just enable the CHANGES tab in the Account and Customer WorkCenter.

      Cheers,

      Davide