Skip to Content
Technical Articles

BRF+, OPD, and custom ABAP code

My requirement was to create a customer statement – easy enough.  The next requirement was a little harder.  It was to use the invoice OPD to determine e-mail or print.  If it was e-mail then where to send it.

To start out, I’m on HANA On-Premise version 1709.

If you need help with setting up OPD, there are some very nice blogs out there:

Output Management via BRF+

New Output Management for Billing

My problem was really not the setup, it was how to add it to my program.   Once I added it, I needed to understand how it worked.  It took me longer than I thought it would.   (By the way you can use this for BFR+ too)  So it was something nice to learn.

So as usual I’m pressed for time.   Let’s get started:

First I found the OPD, in BRF+.   Transaction code BRF+.  Keep in mind this was developed via Webdynpro so switching from client to client you’ll have to sign in on the html page.

Aha – my OPD applications

Next I opened up the billing document.  There was a lot of great information here.  But I needed to find something specific.  So I opened up the function.

At this point you can run a simulation to test what will come up.    Very nice.  You can also do this via the OPD transaction.   In the OPD transaction you can see the data that has been added.  So now I’m switching to OPD as it is easier – at least for me – to work with.

I found the function I really wanted was channel.  So next I started programming.  Here are some snippets.

  data: lo_factory    type ref to if_fdt_factory,
        c_test_app_id type fdt_uuid,
        lo_query      type ref to if_fdt_query,
        lt_ids        type if_fdt_types=>ts_object_id,
        ls_ids        type if_fdt_types=>id.
    lt_ids type sorted table of if_fdt_types=>id
      with unique default key .

  data: lo_fdt_query    type ref to if_fdt_query.

  clear lt_ids.
  call method cl_fdt_query=>get_instance
      ro_query = lo_fdt_query.
* get application id

  call method lo_fdt_query->get_ids
      iv_name       = 'OPD_V3_BILLING_DOCUMENT'
      ets_object_id = lt_ids.

  read table lt_ids into ls_ids index 1.

  "get factory for application
  lo_factory = cl_fdt_factory=>get_instance( exporting iv_application_id = ls_ids ).
*                                 returning c_test_app_id = lo_factory ).

This just pulled in the id that I needed for the billing document.   I retrieved the id for the function.  Now those of you reading this – I skipped some functions.  That was because they were 1 to 1 relationship.  You’ll want to modify for your purpose.  (Try/Catch would be nice to add as well.)

  lo_query = lo_factory->get_query( iv_object_type = if_fdt_constants=>gc_object_type_function ).
      iv_name           = 'FUNC_CHANNEL'
      ets_object_id     = lt_ids ).
  read table lt_ids into ls_ids index 1.
  if sy-subrc = 0.
    gv_channel_id = ls_ids.
* Move to error table

Next was the actual work.  I’ve read not to use the following as it takes too long.  I’ve also read this is the best way  to do it.  I wanted to avoid using the actual ids without the names.

        lo_context->set_value( iv_name = 'OUTPUT_TYPE' ia_value = lv_form ).
        lo_context->set_value( iv_name = 'ROLE' ia_value = lv_role ).
        lo_context->set_value( iv_name = 'BUSINESS_PARTNER_ID' ia_value = lv_kunnr ).

        lv_function_id = gv_channel_id.


            data lt_abap_parbind type abap_parmbind_tab.
            data _v_timestamp2 type if_fdt_types=>timestamp.

            field-symbols <fs_any> type any.

            clear lr_data.
            get reference of lt_out into lr_data.

* Trigger function processing
            assign lr_data->*  to <fs_any>.
            call method cl_fdt_function_process=>process
                iv_function_id = lv_function_id
                iv_timestamp   = _v_timestamp2
                io_context     = lo_context
                ea_result      = <fs_any>
                ct_name_value  = lt_abap_parbind.
            lt_out = <fs_any>.

            read table lt_out into ls_out
                   with key exclusive_ind = abap_true.
            if sy-subrc = 0 and
               ls_out-channel = 'EMAIL'.
              gv_print = abap_false.
              gv_print = abap_true.

Now I had if the document should be e-mailed or printed.   I found that our e-mail addresses were stored in transaction BP and not in the OPD.  So I pulled the default e-mail address.

After you’ve read all this keep in mind.   BRF+ will generate the code for you.  I didn’t like all the hard coding.

BRF+ Basics

You can also take all your coding out of it by generating a function module.  Again this is in BRF+, but OPD is really part of BRF+.  You want to be inside your function.  Then click on tools.  There will be an option to generate a function module.  Again the hard coding made me hesitant to use it. I like more control.

More details in the following and you’ll notice some duplication from my post and this one.  It really helped me a lot.

My learnings in BRF+


Pretty cool.  Now I can think of a lot of uses for BRF+.   Those custom tables that I have that determine something like highest dollar amount, those could easily be switched to BRF+.

That’s my quick example.  Now a challenge – if you have a better way of doing this – please add it in the comments.

You must be Logged on to comment or reply to a post.
  • Very nice!!! I actually like BRF+ a LOT but sadly, it just isn’t used all that much at clients (at least from what I have seen). Not sure why (maybe “another thing” for the tech folks to have to learn?) because it is pretty dang simple to pick up for all the “power” it can give you.

    Keep ’em coming! I like to see actual work in the trenches and not yet another marketing blog disguised as something I might like because it used technical terms in the title. hahaha


    • I’m laughing.  A marketing blog this is not.   But my next paragraph could be considered marketing.

      I bought the BRFPlus Business Rule Management for ABAP Application book.  I’ve gotten to look at it a little but I am still on “hot” projects.  So I haven’t had a chance to use this in any other project yet.

      When I think about all those Z tables I’ve set up over the years to contain generic data, and then had to code if/then/case statements, I just shake my head.   Using BRF+ for all of that makes so much sense.   Of course I may change my mind but I doubt it.

      Thank you for the nice comment!



    • Thank you!  With the way OPD is set up BRF+ is a nice skill to have.   It also can be used in many different places – I think.  I’m going to keep trying to use it when it makes sense.