Skip to Content
Technical Articles

Modify receipt component in SAP Customer Checkout UI

Today I want to show you how you can modify the receipt component in SAP Customer Checkouts UI. Some of these requirements encountered me a couple of times over the last years and since FP11 you are now able to add, remove or modify columns with a plugin.

There is also an influencer ticket to have this configurable in the quick selection management in CCOm. So if you haven’t voted already, please do so.

Customize options for receipt area

This blog post requires some knowledge of creating plugins for SAP Customer Checkout, so I won’t go into these specific details. If you are new to this, please visit my 5 part blog series on CCO plugin development:

SAP Customer Checkout Plugin Development – Part I

So let’s dive into. We all know (and probably love) the receipt component in SAP Customer Checkout .

In this plugin we are going to create, we want to modify the columns shown in the ui. We want to show the itemcode and also the unitprice. Furthermore, we want interact with a click event of the customer, when he clicks on the itemcode. For the sake of simplicity we are going to add a simple alertbox on this click event, but you could also send events in the eventbus or whatever your mind comes up with.

In addition to this, we want to enable the option, that the cashier can edit a sales items description within the current receipt. And yeah, it would be cool, if we can show the cashier, if a sales item is discountable or not. 🙂

So the goal is to let the receipt component looks like this:

 

So how do we achieve this? The UI coding of the quickservice ui now knows the same principle called “Plugin Exits” like we know from the java coding e.g.

@ListenToExit(exitName="BusinessOneServiceWrapper.beforePostInvoiceRequest")

But for our ui plugin we want to listen an exit called “ReceiptComponent.getColumnConfigProvider”. We listen to this exit not in our java coding but rather in our javascript script, we inject with our cco plugin. This procedure on how to do this is explained in detail in my blog series.

What we need to do here is, to provide a new modified configuration for the receipt component. This means, we do not modify the receipt component by modifying tiny bits but rather we provide a complete configuration of the receipt component at once.

The model for the quantity column looks like this:

{
    text: 'ID',
    width: '17%',
    type: 'component',	    			        
    field: 'material.externalID',
    id: 'externalId',
    noAutoFontSize: true,
    component: (cellValue, salesItem) => {	    			        	
        return {
            'component': 'ContainerComponent',
            'props': {
            'margin': '5%',
            'content': {
            'component': 'ButtonComponent',
            'props': {	    			        			
                'content': cellValue,
	    	'btnPress': () => {
	    	    alert(cellValue);
	    	 },
	     'class': 'rowButton'
	     }
	 }
      }	    			        			    			        	
      };	    			        	
   }
 }

So we are setting some properties for this column like the text, the width, the field of the sales item and we can extend this with another component. In this example the externalId column will be treated as a button the cashier can click on. The value for the property “field” can be any field of the sales item data model.

This click event will be handled in ‘btnPress’.

Further properties you can set is a formatter or an editor. Remember when you click on the quantity column in a receipt row? A small editor shows up to let the cashier add or substract items. See:

So we also need to provide this editor as a configuration. The configuration for the quantity column looks like this.

{
    text: receiptComponent.TL('SALES_ITEM_QUANTITY'),
    width: '15%',
    type: 'decimal',
    field: 'quantity',
    id: 'quantity',
    formatter: (cellValue, salesItem) =>
    {
        return cellValue === null ? null : formatters.decimal.formatType(cellValue, decimalTools.TYPE_QUANTITY);
    },
    editor: new cco.ColumnTextEditor(receiptComponent, 'quantity', receiptComponent.TL('ENTER_QUANTITY'), receiptComponent.globalInputStore, receiptComponent.eventBus, null, 'quantity', (model, column) =>
    {
        let salesItem = column.salesItem;

        let fallbackInputModel = new cco.FallbackInputModel(column.text);

        if (receiptComponent.validateQuantityForReturn && salesItem.status !== '1')
        {
            if (salesItem.quantity <= 0)
            {
                fallbackInputModel.setValidator(new cco.MinMaxNumberInputValidator(-salesItem.orderedQuantity, -1));
            }
            else if (salesItem.orderedQuantity > 0)
            {
                fallbackInputModel.setValidator(new cco.MinMaxNumberInputValidator(salesItem.orderedQuantity));
            }
        }
        return fallbackInputModel;
    }, (column) =>
    {
        return !column['salesItem']['voucher'] && !column['salesItem']['immutable'];
    })
}

 

Like the column for the itemcode we are setting some properties like text (in this case translated with the translator), width etc. Also the formatter will be used to format the values of the quantities to the right format. Like I already mentioned, because we provide a full new configuration for the receipt component we also need to implement the editor as well.

The last “special” thing which differs from the standard of the receipt component will be the editor to change the sales item description within the receipt. Also we mark the sales item as discountable. The config for the material description column looks like this:

{
    text: receiptComponent.TL('MATERIAL'),
    width: 'auto',
    type: 'text',
    class: (value, salesItem) => {
        return salesItem.material && salesItem.material.discountable ? 'discountableHighlight' : '';
    },
    field: 'description',
    id: 'description',
    editor: new cco.ColumnTextEditor(receiptComponent, 'description', receiptComponent.TL('DESCRIPTION'), receiptComponent.globalInputStore, receiptComponent.eventBus, null, 'description', (model, column) => {
        let salesItem = column.salesItem;
	
        let fallbackInputModel = new cco.FallbackInputModel(column.text);	    			            
        return fallbackInputModel;
    }, (column) => {
        return !column['salesItem']['voucher'] && !column['salesItem']['immutable'];
    }),
    hints: true
}

We are using the class property (which actually sets the css class for this column) to identify if the salesItem is a discountable item and if so, the class discountableHighlight will be used for this row.

The editor field will be used to use the ColumnTextEditor to let the cashier edit the description of the sales item.

The remaining columns have standard behaviour, so I wont get into more details. The code is uploaded to github as always.

Please feel free to comment.

 

Happy coding!

Robert

3 Comments
You must be Logged on to comment or reply to a post.
  • Hi,

    It is really helpful in understanding the concept of how quick service UI work and also the features you have added will be of use surely.

    I only have one question regarding this, what if I want to show data which is not in salesItemdata for example I want to show another price which I will be fetching through webservice from B1if.

  • Hi Raveed Riaz,

    you could send this additional price in an additional field of the material entity by extending the material sync scenarios. This way, you could easily show it with material.udfDecimal1 (I think).

    When the price needs to be fetched right at the moment, when the article is added to the receipt, you could react on the SALESITEM_ADD event, make the call to the backend and retrieve the price.

    To dynamically change properties of components you can look at the last part of my blogseries, where I introduced the dynamicProperties.

     

    Regards

    Robert

  • Hello Robert!

    Thank you very much for this explanation. In our case the most requested columns are item code, unit of measurement and current stock. The first two are going to be easy with this, the last one I guess we have to try and do it in the way you suggested to Raveed, using an AdditionalField.

    Thank you very much!

    Joerg.