S4HCKS43 – Generating a check digit on your invoice

A check digit to secure BPay payments

It may sometimes be necessary to add information to a document that is made up of other pieces of information (concatenate fields, truncate fields, transform fields, etc…) – that is, information that does not readily exist in your system (like a customer number for example), but can be generated or deduced.

In this snippet we look at how you can add some custom logic in your SAP S/4HANA Cloud system to generate a check digit to a BPay CRN (Customer Reference Number). That is, we want to offer our customer the BPay payment method and for that we have to add to the invoice a CRN number, that will be made of the billing document number appended by a check digit that we will generate on the fly in S/4.

The custom logic to generate the check digit

You will below find the custom logic that I used to generate this check digit (Disclaimer : my code is probably dirty – but it works). I am not checking the length of the billing document number – I have made the assumption that the billing number will always be 8 digits long.

I have also added a screenshot that shows how my custom ‘CheckDigit’ field was defined (Numerical – 1 digit).

* Logic to determine a check digit for a BPay 8 digit CRN number

DATA:
Counter       TYPE i,
lv_billdigit  TYPE i,
lv_total      TYPE i,
lv_billingdoc TYPE string,
lv_chardigit  TYPE string.

Counter = 0.
lv_billingdoc = billingdoc-billingdocument.
SHIFT lv_billingdoc LEFT DELETING LEADING '0'.

While Counter < 8.

   IF ( Counter MOD 2 = 0 ).
      lv_billdigit = lv_billingdoc+Counter(1) * 1 .
   ELSE.
      lv_billdigit = lv_billingdoc+Counter(1) * 2 .
   ENDIF.


   IF ( lv_billdigit > 9 ).
      lv_chardigit = lv_billdigit.
      lv_billdigit = ( lv_chardigit+0(1) ) + ( lv_chardigit+1(1) ).
   ENDIF.


   lv_total = lv_total + lv_billdigit.
   Counter = Counter + 1.
ENDWHILE.


IF ( lv_total MOD 10 = 0 ).
   billingdoc_extension_out-yy1_checkdigit_bdh = 0.
ELSE.
    billingdoc_extension_out-yy1_checkdigit_bdh = 10 - ( lv_total MOD 10 ).
ENDIF.

Video: Generate a - BPay - check digit on your invoices

BPay check tool for Excel

In case you are interested to have it, I am also adding the Excel file that I used to double check the check digit generation. The CRN numbers in the file and check digits were generated on the BPay generator web page. You can download the excel by clicking the icon below.


S4HCKS40 - Create MRP Areas from Excel by leveraging API's

In this snippet we re-visit a previously released snippet : S4HCKS23 Mass Processing Product Master changes in SAP S/4HANA Cloud, but this time leveraging an API that is called from the comfort of MS Excel.

The underlying objective of this snippet, is to show how easy it is to leverage our API’s from third party applications, not just in Read mode, but also in Create/Update Modes. In this snippet we show you how you can supplement your Product Masters with MRP Areas, but this coud apply to any other of the available API’s.

As indicated in the recording, I am providing the excel used in the recording, for you to try out and get some inspiration from. As a disclaimer : You can use it at your own risk – I take no responsibility for you using it. I encourage to first try it in your Q system, with a small dataset. I also remind you not to pass this file to others with either data and / or login credentials !

Some of the important links covered in the recording are:

I must also give credit to Philip Hoffmann, who’s blog provided the file that I have also used to kick start this project. Phillip’s blog also covers how to create a communication user.

I encourage you to read the ‘Read Me First’ tab to get some valuable information, but if you want to just dive right in after you have created your communication user, then you just need to maintain the data you want to upload (MRP_RECORDS tab) and the login credentials as shown below (in the EXEC_DATA tab)

You can download my MRP Areas Excel API file below, by clicking the Excel File icon.


S4HCKS34 Manage your production capacity effectively

In this SAP S/4HANA Cloud Knowledge Snippet – #S4HCKS – we do a deep dive into a new Fiori Application that was released with SAP S/4HANA Cloud 1808. The app in question is Manage Work Center Capacity. You can find more information about this application in the Fiori Apps Library by following this link. You can also check out the application documentation here. If you are unsure where to start to begin exploring this application your self, then Best Practices scope item 31L – Production Capacity Planning and Evaluation– is a good start.

I will let you follow the video for a detailed walkthrough of you need to do in SAP S/4HANA Cloud to be able to fully leverage this application, but before that I will just offer a few pointers, that are also discussed in the recording .

Generate capacity requirements for planned orders

This is not a must and really depends on your situation – i.e is capacity an issue and are you always juggling with the capacity of your bottleneck or key work stations. If so, then you may wish to generate capacity requirements for your planned orders already coming out of MRP, so that you have visibility over the capacity requirement of your production plan over a longer horizon, then that just provided just by the production orders (which you would have only created when needed !).

If so, then you will want to execute the scheduled MRP run, with the scheduling setting ‘2’ – Detailed scheduling. This will have the effect of reading the product’s routing and not not the in-house production lead time in the material! Because you are reading the routing, it means that you are reading the routing’s work centres.

Is your formula enabled to generate capacity requirements?

The formula you will choose in the work centre (or create yourself) is very important, in that, if you miss the setting that will generate a capacity requirement, then you will not see any capacity in the capacity monitoring application! So make sure the ‘WKCtr for rqmts’ check box is active for your selected formula!

Tailor the system to your needs

It may be that you need to create your own formulas, to calculate the capacity requirements of your work centers using a specific formula. No problem, with SAP S/4HANA Cloud you can do that! Just head over the to the Manage your solution application, look for the SSCUI’s in the context Manufacturing / Shop Floor Control / Work Center and create your own formulas.

If you enjoy this post, please consider subscribing to our youtube channel and follow the hashtag #S4HCKS on twitter.

Video: Manage your production capacity effectively


S4HCKS29 Real World solutions with S/4HANA Cloud to real World problems

The stated requirement was to be able to have a KPI tile in the Fiori Launch Pad, that would show a count of the customers that had been able to reach one of two (or both) sales tiers. A sales tier being a sales volume. The numbers are not realistic, but let’s say that tier 1 would represent customers that had been able to reach a sales volume of 1000USD and tier 2 would represent customers that had been able to reach a sales volume of 2000USD. This volume had to be reached over a specific period of time, and if the customer reached one of the two tiers, over that specified period of time, he would then be eligible for a credit (or a rebate if you prefer). The higher the tier achieved, the greater the credit issued. As you can see, using standard features of S/4HANA Cloud, this was achieved quite easily.

The next requirement, was to be able to drill down to a graphical representation of these sales volumes and clearly highlight the two sales tiers (1000USD and 2000USD), so as to be able to instantaneously visualise which customer had reached these tiers. Again, as you can see below, this and much more was achieved using standard capabilities of S/4HANA Cloud. Not only were we able to build the desired graphical representation of the sales volumes and sales tiers, we also added mini charts (mini KPI’s) as well as various evaluations, so as to be able to slice and dice the information in various ways.

So far, the customer brief was met. However, thinking about the use of this data, it quickly becomes evident that the next steps to be taken on the basis of this data, is to be able to issue the due credit to the eligible customers – but how are you going to do it? From the app above, it is possible to present the data in tabular form, you could even add calculated fields in the evaluation of your KPI tile to calculate things such as the amount of the credit. You could also export the data to a spreadsheet and there also calculate the credit due. Then, you are left with the need to create the credit memo in the system. Whilst of course possible, this is fraught with risks (badly slicing the data could lead to over/under issuing credits) and of course immensely tedious – imagine someone entering a large amount of documents in the system manually (again fraught with risks). That said, thanks to S/4HANA Cloud and the power of extensibility there is a much better, faster and leaner way to do this.

What we did, was to use the ‘Custom Business Object’ in S/4HANA Cloud to define a new object – Sales Volumes tiers. The custom business object allows you to define the structure of the object that you need as well as the fields that define this object. In our case we needed fields that would pertain to customers, (customer ID, name, sales organisation…), tiers information (the volume that needed to be achieved as well as the % of the credit that would be issued). Lastly we also wanted to restrict how the volume was going to be measured. I.e was all the customer’s business going to count, or did we want to restrict by a set of materials or materials groups for example. We chose the material group. A snapshot of part of the structure of our Custom Business Object is shown below.

Once the custom business object was created, we then used some coding to realise the magic of the process, namely, to call a CDS to sum the amounts billed to the customer, and on the basis of that determine the amount of the credit to be issued to the customer (if eligible). Then we perform a second call to a whitelisted API to actually create the credit to the customer.

I will let you watch the video recording below to give you a complete view of what we did, but at a high level, in bullet point form below are the main steps/functions:

Creates a custom business object with the required structure and fields.
We added validation logic to make sure the data entered was correct, as expected and was going to play nicely with the subsequent processes
We added some logic, to call the CDS I_BillingDocumentItemCube so as to sum the sales volume of the considered customer.
One the basis of the sales volume determined, and based on the sales targets of the customer, we determine if the customer achieved the Tier 1 or Tier 2 target and if he did, we calculate the corresponding amount of the credit he earned.
We then make a POST call to the whitelisted API API_CREDIT_MEMO_REQUEST_SRV, to actually create the credit memo in the S/4HANA Cloud system.
Looking at these steps, you can imagine the level of automation that was achieved as well as the added value offered!

Video: Real World solutions with S/4HANA Cloud to real World problems


Code Snippets & how-to's

Please check out the blog from my colleague Arun here : https://blogs.sap.com/2018/06/13/mass-update-using-sap-s4hana-cloud-in-app-extensibility/ . His blog will show you what you need to do to setup the required communication arrangements. I would like to thank Arun for his wonderful blog which provided the missing pieces to mine as well as his pointers along the way.

All code provided below is provided as-is. You take full responsibility for using as it nowhere near production grade code.

Below is the code for the first action. It retrieves the sales volumes from the billing CDS and works out the credit due to the customer.

 

* Action Calculate for Node ID sales_volume_rebate
*
* Importing Parameter : association (Navigation to Parent/Child/Associated Node Instances)
* Changing Parameter : sales_volume_rebate (Current Node Data)
* Exporting Parameter : message (Message with Severity S(uccess), W(arning), E(rror))

* -----------------------------------------------------------------------
* calculate bonus
*
DATA: netamount TYPE P DECIMALS 2.
DATA: internetamount TYPE P DECIMALS 2.
DATA: bonus1 TYPE P DECIMALS 2.
DATA: bonus2 TYPE P DECIMALS 2.

IF salesvolumestiers-releasestatus GT '2'.
IF salesvolumestiers-isconsistent = abap_true.

" calculate product bonus
DATA: products TYPE TABLE OF i_productgroup.
DATA: product LIKE LINE OF products.

* get product list from sub node Products
DATA(bonusproducts) = association->to_materialgroups( ).

" get net amount for product
LOOP AT bonusproducts INTO DATA(bonusproduct).
SELECT *
FROM i_productgroup
INTO @product
WHERE i_productgroup~materialgroup = @bonusproduct-materialgroups-materialgroupid.
ENDSELECT.

SELECT
FROM I_BillingDocumentItemCube( p_exchangeratetype = 'M', p_displaycurrency = 'USD' )
FIELDS SUM( SlsVolumeNetAmtInDspCrcy )
WHERE creationdate BETWEEN @salesvolumestiers-validfrom AND @salesvolumestiers-validto
AND SalesOrganization = @salesvolumestiers-salesorg
AND soldtoparty = @salesvolumestiers-soldtoparty
AND materialgroup = @bonusproduct-materialgroups-materialgroupid
INTO @internetamount.

netamount = internetamount + netamount.

ENDLOOP.

salesvolumestiers-volumeachieved_v = netamount.
salesvolumestiers-volumeachieved_c = 'USD'.

if netamount LT salesvolumestiers-targetrevenue1_v.
salesvolumestiers-calculatedbonus_v = 0.
elseif netamount GT salesvolumestiers-targetrevenue2_v.
salesvolumestiers-calculatedbonus_v = ( ( netamount / 100 ) * ( salesvolumestiers-bonusrate2 ) ).
salesvolumestiers-calculatedbonus_c = 'USD'.
else.
salesvolumestiers-calculatedbonus_v = ( ( netamount / 100 ) * ( salesvolumestiers-bonusrate1 ) ).
salesvolumestiers-calculatedbonus_c = 'USD'.
endif.

salesvolumestiers-releasestatus = 4.

ENDIF.
ENDIF.
* SAP CODE BELOW

message = VALUE #(
severity = co_severity-success
text = 'Action CalculateCustomerCredit executed'
).

Then the next piece of code is that which is used create the credit memo per se. Again you will want (have to!) add your own error handling code and execution logic.

* Action CreateCreditMemo for Node ID SALESVOLUMESTIERS
*
* Importing Parameter : association (Navigation to Parent/Child/Associated Node Instances)
* write (API for creating and updating Custom Business Object Node Instances)
* Changing Parameter : SALESVOLUMESTIERS (Current Node Data)
* Exporting Parameter : message (Message with Severity S(uccess), W(arning), E(rror))

CHECK cl_ble_http_client=>is_service_available(
communication_scenario = 'YY1_INT_HTTP'
outbound_service = 'YY1_INT_HTTP_REST'
) = abap_true.

DATA(lo_client) = cl_ble_http_client=>create(
communication_scenario = 'YY1_INT_HTTP'
outbound_service = 'YY1_INT_HTTP_REST'
).

* we get the csrf token to be able to make the POST call later
DATA(request) = cl_ble_http_request=>create( ).
DATA lv_s2 TYPE string VALUE '/API_CREDIT_MEMO_REQUEST_SRV/A_CreditMemoRequest?%24top=1&%24format=json'.
request->set_header_parameter( exporting name = 'X-CSRF-TOKEN' value = 'FETCH' ).
request->set_method( 'GET' )->set_resource_extension( lv_s2 ).
TRY .
DATA(response) = lo_client->send( request ).
DATA(lv_csrf) = response->get_header_parameter( 'x-csrf-token' ).
CATCH cx_ble_http_exception INTO DATA(l5).
ENDTRY.

* We build the payload that will be submitted in the POST call
* We will also convert the calculated bonus to a string so that the call plays nicely
DATA: lv_payload TYPE string,
calcbonus TYPE string,
lv_pl41 TYPE string value '{"d" : { "PurchaseOrderByCustomer": "CREDIT-2018- ',
lv_pl42 TYPE string value '","SoldToParty": "',
lv_pl43 TYPE string value '","SalesOrganization":"',
lv_pl44 TYPE string value '","CreditMemoRequestType":"CR","OrganizationDivision":"00","DistributionChannel":"10",',
lv_pl45 TYPE string value '"to_Item": [ { "Material": "CREDIT","RequestedQuantity": "1","to_PricingElement": [ {',
lv_pl46 TYPE string value '"ConditionType":"PPR0","ConditionRateValue": "',
lv_pl47 TYPE string value '","ConditionCurrency":"',
lv_pl48 TYPE string value '"} ] } ] } }'.

* We retrieve the calculated bonus from the custom business object
calcbonus = salesvolumestiers-calculatedbonus_v.
* We get rid of the trailing space that is added to the calculated bonus
CONDENSE calcbonus.

* we concatenate the various fields that will make up the payload
CONCATENATE lv_pl41 salesvolumestiers-soldtoparty lv_pl42 salesvolumestiers-soldtoparty lv_pl43
salesvolumestiers-salesorg lv_pl44 lv_pl45 lv_pl46
calcbonus lv_pl47
salesvolumestiers-calculatedbonus_c lv_pl48 INTO lv_payload.

* we make the POST call to the credit memo request API
DATA(request1) = cl_ble_http_request=>create( ).
DATA lv_s1 TYPE string VALUE '/API_CREDIT_MEMO_REQUEST_SRV/A_CreditMemoRequest'.
request1->set_header_parameter( exporting name = 'x-csrf-token' value = lv_csrf ).
request1->set_content_type( 'application/json' ).
request1->set_method( 'POST' )->set_resource_extension( lv_s1 ).
request1->set_body( lv_payload ).

TRY .
DATA(response1) = lo_client->send( request1 ).
CATCH cx_ble_http_exception INTO DATA(lx1).
ENDTRY.

* We also want to be able to update the custom business object with the created credit memo number
* So we will use regular expressions to find the content of the tag in the response
DATA result TYPE match_result_tab.
DATA line LIKE LINE OF result.
DATA sub TYPE submatch_result.
DATA output TYPE string.
DATA lx60 TYPE string.
output = response1->get_body( ).

FIND ALL OCCURRENCES OF REGEX '((?:[^<]| LOOP AT result INTO line.
LOOP AT line-submatches INTO sub.
lx60 = output+sub-offset(sub-length).
ENDLOOP.
ENDLOOP.

* We update the custom business object field Credit Memo with the credit memo number just created
salesvolumestiers-creditmemo = lx60.

message = VALUE #(
severity = co_severity-success
text = 'Credit Memo Created:'
&& lx60
).

Share on Social Media


SAP Batch Determination made easy

Recently a colleague encountered the following problem:

His customer tracks perishable products that are bought / inventory managed / sold using the SAP functionality Batch Management (LO-BM). The products have a shelf life and therefore a “Use by/Expiration” date. His problem was that he was able to correctly update the characteristic “Expiration date” of the batch, but was not able to select batches during the delivery stage, based on the “Expiration date” – i.e batches that were still fit for use.

So here is a tutorial on how to select batches during the delivery (but it could be applied to any batch search requirement) for which the shelf life has not expired. It has to be noted that SAP covers all kinds of scenario.

– It might be company practice to ship out the door products with a minimum shelf life of X days
– It might be that a specific customer requires a product with a different, longer minimum remaining shelf life
– It might also be that products that are shipped to a specific country require a yet again different minimum shelf life

It might be that you require all three or a logical combination of all three. SAP will easily cover all those requirements and more.

This tutorial only covers the batch determination process in SD, but once you get the jist of it you should be able to apply this to any other module where that function is covered. I also assume that you have set up your system in such way that you are able to have products batch managed.

Step 1 – Standard SAP characteristics you will import

The first thing you need to do is to check that your SAP client has all the required SAP standard characteristics. To do this go to transaction CT04 and query your system to find all characteristics that are called LOBM*.

If a list of values such as the one below is returned then it means that you are all set to go to Step 2 – Create and assign Batch class to products.

If not it means that you need to copy them from client 000. To do that go to customizing and follow the path indicated: Customizing / Logistics – General / Batch Management / Batch Valuation / Updates Standard Characteristics (or transaction BMSM)

The following messages will be displayed if everything goes well.

Once that is done you might want to go back to transaction CT04 and query for characteristics called LOBM*.

Why do I need to do that do you ask? Well for one thing all the work is done for you. Secondly and more importantly the standard SAP functions that will enable us to dynamically calculate the “Expiration date” based on minimum remaining shelf life, makes use of these standard characteristics – they are hard coded in the ABAP functions.

Moving on to step 2 and getting your basic data right.

Step 2 – Create and assign Batch class to products you will do

In our case we have one product, to which we have assigned one class (of technical type 023 – batches). This class has been conveniently called “EXPIRATION” and contains only one characteristic. That characteristic is one of the standard SAP ones called “LOBM_VFDAT – Expiration date, shelf life”. The system has been set up in such a way that when ever I do a goods receipt on this product, SAP will ask me to input the production date and then based on the shelf life of the product, automatically calculate the expiration date of my batch.

This will update a standard SAP table field (MCHA-VFDAT / MCH1-VFDAT – depending on the validity of your batch across plants). This will in turn update the value of the characteristics LOBM-VFDAT within the batch .

So if we look at the shelf life list report (transaction MB5M) we see that this information concurs with that contained in the classification of our batches.

Step 3 – Create a Batch search class you will do

This is a class that will be used to search and find applicable batches during batch determination. It is not directly assigned to the product – it will be assigned to the batch search strategy of the product.

The question is, what characteristics should we put in this class?

If we go back to basics, what we will want to do, is find batches that have a remaining shelf life of X days. If we view this requirement in a different way, we can say that we will want to find batches that have an expiry date that is equal or greater to “delivery date + X days” . My class will therefore use the following characteristics:
– LOBM-VFDAT : The expiration date of the batch – that value SAP will calculate.
– LOBM-LFDAT : The delivery date – that value will be automatically updated by SAP with the delivery date from the delivery

All we need is a characteristic where we will be able to input the value corresponding to X (minimum remaining shelf life required). Again, we do not need to do anything, SAP provides the characteristic “LOBM_RLZ – Remaining Shelf Life for Batch”, to do just that. We therefore have a class (also of technical type 023 – batches) that looks like this.

Step 4 – Create a sort rule you will do

It’s all good to build a batch search class to find batches, but assuming SAP finds numerous batches, how should they be sorted (i.e which should be the first one used?) ? By batch number? Of course not, we want to sort batches based on the expiration date in ascending order (the batches with the date closest to the present should be the first to go).

To do this, call transaction CU70.

Give your sort sequence a name and in the following screen, give it a description as well.

Then click on the characteristics button and assign the characteristic LOBM-VFDAT to it. Also select/amend the sort order that you want.

Save your sort key.

Step 5 – Create a batch search strategy you will do

We want to create a search strategy during delivery processing, i.e in SD – Sales and distribution. So call transaction VCH1 – to create it. We’ll create a strategy determined based on the customer and the material (standard strategy type SD01 caters for that).

Enter your customer and product (amend the strategy as required).

Click on the “selection Criteria” button to assign the search class. In this case we indicated our search class, which copied across the characteristics associated with it.
We also indicate the value “>=30” in the characteristic “Remaining Shelf Life for Batch” – this means that we will only want to select batches that have an expiration date that is greater or equal to delivery date + 30 days.

Now go back to the previous screen and now click on the “sort” button. There you will assign the sort rule you created in the previous step.

Save your work.

Step 6 – Putting it into practice - the fruit of your efforts you will see

Now that we have created all the required basic data, let’s see how it all hangs together.

We have a sales order for which we create a delivery – batch search will be triggered manually to better follow the process.
In the delivery, we go to the batch determination screen and we see that the system has automatically searched, found and proposed batches that have a remaining shelf life that is greater or equal to 30 days only and it has sorted them according to expiration date – just what we wanted.

The system here proposes 3 batches (yet remember that above, it did indicate that we had 5 batches in the system). To get a better idea of what parameters were calculated/used to determine those three batches, click on the “selection criteria button”.

We see the >=30 that we typed in the batch search strategy. We also see that the system took the delivery date “08.09.2008” added 30 days to it and determined that the batch it was going to search for had to have an expiration date greater or equal to 08.10.2008.

We can also change the search parameters here (this is customizable). We’ll change the value of 30 to 4 right there in the batch determination.

This shows even more batches – logical as we have indicated that batches should only have a remaining shelf life of 4 days or more.