Skip to Content
Technical Articles
Author's profile photo Uladzislau Pralat

S/4HANA Manage Customer Line Items App – Advanced Fields Extension

SAP documentation explains how to extend S/4HANA Manage Customer Line Items App with custom fields, but it is a very simplistic example. In my blog I will explain how to make advanced fields extensions:

Custom field with a total as a sum of line item values

In my example, I have 3 custom amount fields – Credit, Deduction and Invoice. These amounts are calculated on line item level and depends on Amount sign and Journal Entry Type. Totals for these fields is a sum of line item level calculations.

Custom field extension is advanced to handle multiple currencies as well.

Why it is so complex that SAP documentation example does not cover that? The way Manage Customer Line Items app work it calls FAR_CUSTOMER_LINE_ITEMS OData service two times: for line items and for totals.

During totals call only amounts and units of measure fields are read. There is no information about line item level values.The way advanced extension works it additionally reads information on line item level, calculates totals as a sum of line item values and map custom field totals into entity set.

Advanced extension manipulates request content adding properties that custom amount fields calculation depends on prior to reading data.

Custom field enabled for filtering

I my example, there 2 custom fields that are enabled for filtering: Amount Type and Aging Group. Amount Type depends amount sign and document type. Aging group depends on Days in Arrears

Why it is so complex that SAP documentation example does not cover that? Because it is very complex and risky enhancement. If it is not done right it can mess up a whole application: line item selection, standard fields totals and paging.

Custom fields filters are not handled by standard FAR_CUSTOMER_LINE_ITEMS OData service. That is why custom fields filter values are removed from request context prior to reading data. Custom fields filter values are applied in extension.

Custom fields filters impacts standard fields totals. That is why standard field totals are re-calculated along with custom fields totals and mapped into entity set.

Applying custom fields filters impacts paging since entity set records count might be reduced or even become 0. Advanced extension takes over paging handling completely:

  • Reads entire entity set (skip 0, first 1000000), applies custom fields
  • Takes entire entity set record count and overwrites incline count
  • Return only subset of entire entity set applying (applying skip and first requested by Fiori)

Manage Customer Line Items app custom field advanced extension step by step

Add append structure with custom fields to FAR_IFIARLINEITEM_EX structure

Enhance /IWBEP/CL_MGW_REQUEST class adding custom methods

Create SEGW project and redefine FAR_CUSTOMER_LINE_ITEMS OData Service

Add custom fields properties to Item entity type

Redefine DEFINE method in metadata provider extension class

Add service methods to ZCL_ZFAR_CUSTOMER_LINE_DPC_EXT class

Redefine ITEMSET_GET_ENTITYSET method in data provider extension class

METHOD itemset_get_entityset.
FIELD-SYMBOLS: <s_entityset> TYPE cl_far_customer_line_i_mpc=>ts_item.
CONSTANTS: c_top TYPE i VALUE 1000000.

* Get Information about Request Context (IO_TECH_REQUEST_CONTEXT)
  DATA(request_context) = CAST /iwbep/cl_mgw_request( io_tech_request_context ).
  DATA(model) = request_context->get_model( ).
  DATA(wt_headers) = request_context->get_request_headers( ).
  DATA(ws_request_details) = request_context->get_request_details( ).
* Delete custom filter proprties that not supported by standard data provider
  delete_filter_properties(
    EXPORTING
      it_field_name      = VALUE #( ( CONV string( 'AmountType' ) )
                                    ( CONV string( 'AgingGroup' ) ) )
    CHANGING
      cs_request_details = ws_request_details  ).
  DATA(wt_filter_select_options) = it_filter_select_options.
  DELETE wt_filter_select_options WHERE property = 'AmountType'
                                     OR property = 'AgingGroup'.
* Check if totals are read
  DATA(w_total) = is_total( is_request_details = ws_request_details
                            io_model           = model ).
* Check if custom properties totals or filters required
  IF ( w_total = abap_true ) AND
     ( line_exists( ws_request_details-select_params[ table_line = 'AmountInvoice' ] ) OR
       line_exists( ws_request_details-select_params[ table_line = 'AmountDeduction' ] ) OR
       line_exists( ws_request_details-select_params[ table_line = 'AmountCredit' ] ) OR
       line_exists( it_filter_select_options[ property = 'AmountType' ] ) OR
       line_exists( it_filter_select_options[ property = 'AgingGroup' ] ) ).
*   Add standard fields that are required to calculate custom fields totals
    add_select_properties(
      EXPORTING
        it_field_name      = VALUE #( ( CONV string( 'COMPANYCODE' ) )
                                      ( CONV string( 'ACCOUNTINGDOCUMENT' ) )
                                      ( CONV string( 'FISCALYEAR' ) )
                                      ( CONV string( 'ACCOUNTINGDOCUMENTITEM' ) )
                                      ( CONV string( 'VH_COMPANYCODECURRENCY' ) )
                                      ( CONV string( 'VH_ACCOUNTINGDOCUMENTTYPE' ) )
                                      ( CONV string( 'VH_AMOUNTINCOMPANYCODECURRENCY' ) )
                                      ( CONV string( 'NETDUEARREARSDAYS' ) ) )
      CHANGING
        cs_request_details = ws_request_details ).
*   Change paging to read all line information at document item level
    DATA(ws_paging) = VALUE /iwbep/s_mgw_paging( skip = 0
                                                 top = c_top ).
    ws_request_details-paging = VALUE #( skip = 0
                                         top  = c_top ).
*   Create modified Request Context (IO_TECH_REQUEST_CONTEXT)
    DATA(tech_request_context) =
      NEW /iwbep/cl_mgw_request(
        ir_request_details = ref #( ws_request_details )
        it_headers = wt_headers
        io_model = model ).
*   Get entity set
    super->itemset_get_entityset(
      EXPORTING
        iv_entity_name = iv_entity_name
        iv_entity_set_name = iv_entity_set_name
        iv_source_name = iv_source_name
        it_filter_select_options = wt_filter_select_options
        is_paging = ws_paging
        it_key_tab = it_key_tab
        it_navigation_path = it_navigation_path
        it_order = it_order
        iv_filter_string = iv_filter_string
        iv_search_string         = iv_search_string
        io_tech_request_context = tech_request_context
      IMPORTING
        et_entityset = et_entityset
        es_response_context = es_response_context ).
    LOOP AT et_entityset ASSIGNING <s_entityset>.
*     Apply custom properties filter
      IF line_exists( it_filter_select_options[ property = 'AmountType' ] ).
        IF get_amount_type( <s_entityset> ) NOT IN it_filter_select_options[ property = 'AmountType' ]-select_options.
          DELETE et_entityset.
          CONTINUE.
        ENDIF.
      ENDIF.
      IF line_exists( it_filter_select_options[ property = 'AgingGroup' ] ).
        IF get_aging_group( <s_entityset> ) NOT IN it_filter_select_options[ property = 'AgingGroup' ]-select_options.
          DELETE et_entityset.
          CONTINUE.
        ENDIF.
      ENDIF.
*     Calculate custom properties
      <s_entityset>-amountinvoice = get_amount_invoice( <s_entityset> ).
      <s_entityset>-amountdeduction = get_amount_deduction( <s_entityset> ).
      <s_entityset>-amountcredit = get_amount_credit( <s_entityset> ).
    ENDLOOP.
*   Calculate totals
    get_total(
      EXPORTING
       is_request_details = ws_request_details
       it_entityset       = et_entityset
       io_model           = model
      IMPORTING
       et_entityset       = DATA(wt_entityset_total) ).
  ENDIF.

* Getting information about Request Context (IO_TECH_REQUEST_CONTEXT) again
  request_context = cast /iwbep/cl_mgw_request( io_tech_request_context ).
  ws_request_details = request_context->get_request_details( ).
* Delete custom properties filtering
  delete_filter_properties(
    EXPORTING
      it_field_name      = VALUE #( ( CONV string( 'AmountType' ) )
                                    ( CONV string( 'AgingGroup' ) ) )
    CHANGING
      cs_request_details = ws_request_details  ).

* Check if custom fields are requested
  IF ( line_exists( ws_request_details-select_params[ table_line = 'AmountInvoice' ] ) OR
       line_exists( ws_request_details-select_params[ table_line = 'AmountDeduction' ] ) OR
       line_exists( ws_request_details-select_params[ table_line = 'AmountCredit' ] ) OR
       line_exists( ws_request_details-select_params[ table_line = 'AmountType' ] ) OR
       line_exists( ws_request_details-select_params[ table_line = 'AgingGroup' ] ) OR
       line_exists( it_filter_select_options[ property = 'AmountType' ] ) OR
       line_exists( it_filter_select_options[ property = 'AgingGroup' ] ) )  AND
       w_total = abap_false.
*   Add standard fields that are required for custome fields calculation
    add_select_properties(
      EXPORTING
        it_field_name      = VALUE #( ( CONV string( 'COMPANYCODE' ) )
                                      ( CONV string( 'ACCOUNTINGDOCUMENT' ) )
                                      ( CONV string( 'FISCALYEAR' ) )
                                      ( CONV string( 'ACCOUNTINGDOCUMENTITEM' ) )
                                      ( CONV string( 'VH_ACCOUNTINGDOCUMENTTYPE' ) )
                                      ( CONV string( 'VH_AMOUNTINCOMPANYCODECURRENCY' ) )
                                      ( CONV string( 'NETDUEARREARSDAYS' ) ) )
      CHANGING
        cs_request_details = ws_request_details ).
  ENDIF.
  ws_paging = is_paging.
* Read all data before applying custom property filters
  IF w_total = abap_false AND ( line_exists( it_filter_select_options[ property = 'AmountType' ] ) OR
                                line_exists( it_filter_select_options[ property = 'AgingGroup' ] ) ).
    ws_paging = VALUE #( skip = 0
                         top = c_top ).
    ws_request_details-paging = VALUE #( skip = 0
                                         top  = c_top ).
  ENDIF.
* Create modified Request Context (IO_TECH_REQUEST_CONTEXT)
  tech_request_context =
    NEW /iwbep/cl_mgw_request(
      ir_request_details = REF #( ws_request_details )
      it_headers = wt_headers
      io_model = model ).
* Get entity set
  super->itemset_get_entityset(
    EXPORTING
      iv_entity_name = iv_entity_name
      iv_entity_set_name = iv_entity_set_name
      iv_source_name = iv_source_name
      it_filter_select_options = wt_filter_select_options
      is_paging = ws_paging
      it_key_tab = it_key_tab
      it_navigation_path = it_navigation_path
      it_order = it_order
      iv_filter_string = iv_filter_string
      iv_search_string         = iv_search_string
      io_tech_request_context = tech_request_context
    IMPORTING
      et_entityset = et_entityset
      es_response_context = es_response_context ).
*
  LOOP AT et_entityset ASSIGNING <s_entityset>.
*   Apply customer properties filter
    IF w_total = abap_false AND line_exists( it_filter_select_options[ property = 'AmountType' ] ).
      IF get_amount_type( <s_entityset> ) NOT IN it_filter_select_options[ property = 'AmountType' ]-select_options.
        DELETE et_entityset.
        CONTINUE.
      ENDIF.
    ENDIF.
    IF w_total = abap_false AND line_exists( it_filter_select_options[ property = 'AgingGroup' ] ).
      IF get_aging_group( <s_entityset> ) NOT IN it_filter_select_options[ property = 'AgingGroup' ]-select_options.
        DELETE et_entityset.
        CONTINUE.
      ENDIF.
    ENDIF.
    IF line_exists( ws_request_details-select_params[ table_line = 'AmountType' ] ).
      <s_entityset>-amounttype = get_amount_type( <s_entityset> ).
    ENDIF.
    IF line_exists( ws_request_details-select_params[ table_line = 'AgingGroup' ] ).
      <s_entityset>-aginggroup = get_aging_group( <s_entityset> ).
    ENDIF.
    IF ( w_total = abap_false ) AND
       ( line_exists( ws_request_details-select_params[ table_line = 'AmountInvoice' ] ) OR
         line_exists( ws_request_details-select_params[ table_line = 'AmountDeduction' ] ) OR
         line_exists( ws_request_details-select_params[ table_line = 'AmountCredit' ] ) ).
       <s_entityset>-amountinvoice   = get_amount_invoice( <s_entityset> ).
       <s_entityset>-amountdeduction = get_amount_deduction( <s_entityset> ).
       <s_entityset>-amountcredit    = get_amount_credit( <s_entityset> ).
    ENDIF.
    IF ( w_total = abap_true ) AND
       ( line_exists( ws_request_details-select_params[ table_line = 'AmountInvoice' ] ) OR
         line_exists( ws_request_details-select_params[ table_line = 'AmountDeduction' ] ) OR
         line_exists( ws_request_details-select_params[ table_line = 'AmountCredit' ] ) OR
         line_exists( it_filter_select_options[ property = 'AmountType' ] ) OR
         line_exists( it_filter_select_options[ property = 'AgingGroup' ] ) ).
      map_total(
        EXPORTING
          is_request_details       = ws_request_details
          it_entityset             = wt_entityset_total
          it_filter_select_options = it_filter_select_options
          io_model                 = model
        CHANGING
          cs_entityset             = <s_entityset> ).
    ENDIF.
  ENDLOOP.
  IF w_total = abap_false AND ( line_exists( it_filter_select_options[ property = 'AmountType' ] ) OR
                                line_exists( it_filter_select_options[ property = 'AgingGroup' ] ) ).
*   Change inline count after applying custom properties filter
    es_response_context-inlinecount = LINES( et_entityset ).
*   Return only portion of data requested by client after applying custom properties filter
    DATA(wt_entityset) = et_entityset.
    CLEAR: et_entityset.
    APPEND LINES OF wt_entityset
      FROM ( is_paging-skip + 1 ) TO ( is_paging-skip + is_paging-top )
      TO et_entityset.
  ENDIF.

ENDMETHOD.

The same source code can be downloaded from GitHub:

 

Assigned Tags

      26 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Filip Nespor
      Filip Nespor

      Good job and thanks for sharing this with other customers/consultants.

      Author's profile photo Youri Catinat
      Youri Catinat

      Thanks for this post.

      Could you explain why this step is necessary ?

      This code is used in the method "itemset_get_entityset" OK, but I would like to understand why it is necessary.

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Youri,

      because mo_model and mt_headers are not publicly accessible.

      Regards, Uladzislau

      Author's profile photo Venkat dattatreya
      Venkat dattatreya

      you can create model instead of enhancement and use it in your extension

        DATA lo_model             TYPE REF TO /iwbep/if_mgw_odata_fw_model.

       lo_model ?= lo_metadata_provider->get_service_metadata(

      iv_internal_service_name    '<SERVICE NAME>
      iv_internal_service_version = <VERSION NO OF ODATA SERVICE>

      ).

      Author's profile photo Smriti Gupta
      Smriti Gupta

      Hi,

       

      Many thanks for this useful blog. It was super helpful in extending the app with custom fields. I also added the field as a filter. However the filter is not working when the results are grouped on some field. Also sorting is not working.

      If we extend the field in the interface view I_ARLINEITEM, can the sorting and grouping work then?

      Could you please let me know how can I make the custom filter work with grouping? ie. I group the records on Customer number and then want to select the value in custom filter

      Many thanks

      Smriti

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Hi Smriti,

      glad that you found my blog helpful. Now you know as much as I know on this subject. I overlooked grouping and sorting with custom filters in my testing. With some minor fixes, I am sure, you will make it work. Please share with the community once you find a solution.

      Regards, Uladzislau

       

      Author's profile photo himanshu sahu
      himanshu sahu

      HI Uladzislau,

      Many thanks for very nice blog, i have some query regarding manage customer line items app.

      I have the same requirement to add a filter(Sales District) and two fields for Fiori App ID F0711.

      can it be done by following steps

      1. extend  CDS view I_ARLINEITEM with two fields
      2. extend redefine the standard OData and add these two fields to entity item.

      Please suggest.

      Thanks

      Himanshu

      Author's profile photo Jenise Amoah
      Jenise Amoah

      Hi,

      Thank you for this amazing blog @Uladzislau Pralat.

      @Smriti I am experiencing the same issue. Could you please share if you've found a solution?

       

      Thank you.

       

      Jenise

      Author's profile photo Sushant Nath
      Sushant Nath

      Hello Uladzislau,

       

      Hope you are doing good!

      Thanks for sharing, a valuable blog/post, to enhance the standard app "Manage customer line items".

      We have extended/enhanced the app, with a custom filter named as "Payment block" and it working fine as well.

      However, now we need suggestions/assisted help, on the "Payment block" field like "Customer" field.

      PFA a screenshot, supporting the same.

       

       

      May I know, if you have any suggestions, for this?

       

      Best Regards,

      Sushant

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Hi Sushant,

      my blog covers both how to add custom field and enable it for filtering.

      Regards, Uladzislau

       

      Author's profile photo Sushant Nath
      Sushant Nath

      Hello Uladzislau,

      Thanks for looking into this issue.

      We have achieved, adding and filtering of custom custom fields, using this blog.

      However, now we  need, suggestions/assisted/match code functionality, on the custom fields "Release Group", as per screenshot, similar to "company code".

      May i know, if this is covered in this blog?

      If not, may I know, if you have any inputs on this?

      Best Regards,

      Sushant

       

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Hi Sushant,

      it is not covered in the blog, but it is done for number of fields in standard implementation. All you need to do is see how it is done and do the same.

      Regards, Uladzislau

       

      Author's profile photo Mayank Jaiswal
      Mayank Jaiswal

      Hi Pralat,

      Thanks for the blog, your blogs are always real time scenarios based, so I like to go about it whether I have the background of it or not.

      Just a small request, can you please throw some light on DPC classes and which all scenarios requires to use this approach in Embedded Analytics. Do you have some useful blogs or link pointing out the same.

      Best Regards,

      Mayank

      Author's profile photo Tulio Tsuruda
      Tulio Tsuruda

      Hi Uladzislau Pralat!

      Greats for share your knowledge!
      I`'m facing a problem with this same Application, F0711.

      I've extened the OData, but i didn't set the Overwrite Base/Extended Service checkbox because of.. what if any problem occurs?

      So, that is the only difference between what I did and what you show us.

      Therefore, to use my new 'Z' OData, I do extended the BSP project FIN_CUST_LITS and I've created a extension of that and I "redefined" the manifest to call the new OData server.

      So far so good, the new extened App and project worked fine, but we got one problem that we couldn't found a solution.

      No one date field doesn't works!

      We've extended the OData to append new fields. We redefine the method ITEMSET_GET_ENTITYSET to set what we want to display on it.But, all of date fields doesn't showup any value. Any other fields is work softly.

      The%20two%20scenarios%20are%20in%20the%20same%20environment

      The two scenarios are in the same environment

      To ensure the same fetch data, we call the SUPER class and the method ITEMSET_GET_ENTITYSET. After retrive data we treat the value of our Zfield.

       

      So... Anyone can help with this problem?

      Author's profile photo Tulio Tsuruda
      Tulio Tsuruda

      Solved!

      My problem it was due to our Z filed was between the Standard fiels in the properties on the Entity Item. So, I just placed our Z filed in the end and done!!!

      Author's profile photo Tulio Tsuruda
      Tulio Tsuruda

      Hi Uladzislau Pralat and experts!

      Me again, with this same application.

      After done the extension/enhaces my application extented doesn't work the Search Help and Suggestion.

      In the standard application still works, but in my extented for no reason why, it doesn't work.

      The Z metadata and standard metadata, show all annotation of Search Help.

      Standard%20anda%20OData%20Z%20with%20Search%20Help%20Annotation

      Standard anda OData Z with Search Help Annotation

       

      Follow down, there are the comparation of OData services.

       

       

      Below, I'm showing our redefine method DEFINE, that i treat the Z field to display as Date, but there are a attempt to force a new annotation to display a Search Help.

       

      The new annoation in our Z OData

       

      But, even with that, it didn't work!

      While I'm looking for find some problem I noticed that the frameworks are doesn't get the right entity. Standard are getting the VL_SH_DEBIA, but Z it doesn't. I dont know why it is happen

       

      Below i'm showing that Entity VL_SH_DEBIA exists and works in Z OData.

       

      So, please, there are someone can help. I don't know what can I do or look for the fix this problem.

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Hi Tulio,

      each requirement is unique and requires detailed investigation and testing. In your case, if think, some related changes are not done or incorrect.

      Regards  Uladzislau

      Author's profile photo Tulio Tsuruda
      Tulio Tsuruda

      Thx reply, Uladzislau!

      I did every think right I supposed!

      My requiremente was simple. They wanted just a new date column.
      So, my steps were:

      1. Append a new field in FAR_IFIARLINEITEM_EX;
      2. Enhance the OData Standard and redefine him creating a New Z
      3. Append the new field in Entity Item
      4. Redefined the ITEMSET_GET_ENTITYSET to fillup the Z field
      5. Create a Extensibility App for FIN_CUST_LITS using Web IDE
      6. And, I "redefine" the manifest.json to overwrite the Standard OData

      I%20highlighted%20just%20what%20I%20did

      I highlighted just what I did

      It was all I did.

      Different what you did, I didn't Overwrite Base/Extended Service, because in other OData, an ABAP did it and get some problem with the APP. So he tried to rollback and the APP doesn't work anymore.

      When you overwrited do Standard OData you no needed to extented a new App, right?

      Do you have any suggest what I could do or looking for?

      I tried to make the same steps that SAP exposed here. But, some step we can't do, like create a SAPUI5 in Eclipse. And even with not using metadata and set the Component.js, the extended APP ignored the Z OData.

      So I'm completely lost what I can do now.

      Author's profile photo Venkat dattatreya
      Venkat dattatreya

      Hello,

      Yes there is no need to create new Odata service in /IWFND/MAINT_SERVICE on your SEGW project and no need of Fiori(FIN_CUST_LITS) extension project. Just do redefine the odata and override the base service while generating the classes and MDL. After that redefine your methods to add your custom code after calling the super method.

      If you want to delete the service( *_SRV) use Tcode /IWBEP/REG_SERVICE.

       

      Thank you.

      Author's profile photo Ashok Gadde
      Ashok Gadde

      Hi ,

       

      I am facing the same issue , did you find any solution for Value Helps ?

       

      Author's profile photo Ashok Gadde
      Ashok Gadde

      Hello,

       

      I want to add a custom field in the Manage Customer Line Items APP . Followed below steps

      1. Append a new field in FAR_IFIARLINEITEM_EX;
      2. Created a custom OData project  and right click on data model to redefine using standard OData project and selected the entity type where a field to be added.
      3. Append the new field in Entity Item
      4. Redefined the ITEMSET_GET_ENTITYSET and included custom logic to fill the field.

       

      what are the steps to make custom field  visible in UI  and when i redefine the standard gateway OData service i see annotations are missing and date fields in the app are not displaying the content

      Can any one please suggest what exactly am i missing ?

      Author's profile photo Ashok Gadde
      Ashok Gadde

      Hi Uladzislau Pralat,

       

      I have to add a new description field in the F0711 app.

      1. Append a new field in FAR_IFIARLINEITEM_EX;
      2. Enhance the OData Standard and redefine him creating a New Z
      3. Append the new field in Entity Item
      4. Redefined the ITEMSET_GET_ENTITYSET to fillup the Z field
      5. created a adoption project in BTP and replaced odata URI.
      6. I am missing the F4 helps for the customer and company code and all date fields as well.

      Can you anyone suggest ?

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Hi Ashok,

      thank for proper testing my solution. I think, to solve the issue some other method(s) need to be extended.

      Regards, Uladzislau

      Author's profile photo Jimmy Moreno
      Jimmy Moreno
      Hi Uladzislau.
      Are there any way to extend the fields of Edit Line Items button? I need to add two custom fields
      image.png
      Thanks in advance.
      Jimmy
      Author's profile photo Jimmy Moreno
      Jimmy Moreno

      Hi Uladzislau.

      Are there any way to extend fields of Edit Line Item button?. I tried with Data Source Extensions FAP_VENDOR_LINE_ITEMS_SRV. Please can you help me?

      image.png

      Thanks in advance.

       

      Jimmy

      Author's profile photo Uladzislau Pralat
      Uladzislau Pralat
      Blog Post Author

      Hi Jimmy,

      I have not had chance to work on such requirement. Please share your experience with the community.

      Regards, Uladzislau