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.

  • Hi folks, very helpfully

    I am struggling looking a way to determine the Form Template Country in output control for PURCHASE ORDER, user needs to enter manually every time they need to send by EMAIL the PO even when the message is determined correctly but Template Country field remains in blank, any clue to determine this field automatically?


    • I believe you are looking for the t001 table.   SPRO->Enterprise Structure->Definition->Financial Accounting->Edit, Copy, Delete, Check Company Code ->Edit Company Code Data.  Enter the Country for the company code.

  • /
    • OK – I’ll look a bit more.   Country code is usually supplied on the SAP backend.   Not in the output determination.  It is used in output determination, as you noted, in finding the e-mail.

      What version are you on?  Are you in the cloud or on-premise?

    • OK – I’ll try.   Country is defined in different places.   So a lot of it depends on what you have configured.

      You checked company.

      • In configuration – I believe – you can check the plant/storage location combination.  In configuration check the sales organization.
      • Check the purchase organization in SPRO.


      The next thing I would do is check the master data.

      • check the vendor in transaction BP.  Display the financial Services role and check it.

      How is your PO created?  Check the transaction data.

      • If it’s create from a sales order – take a look at the sales order.   What country was used?
      • If it’s created from the purchase transaction without referencing a purchase requisition.   Then it should automatically be filled.   But take a look at the purchase order anyway.
      • If it’s created from an info-record, take a look at the info-record.  Is country filled in?
      • Is there any custom code used?  Could it effect the country?

      Last but not least, try posting a question in the forums.  Their are a lot more people there who might help you out.    Remember when you post, it is not a problem with Output Determination.   It is a problem with the purchase order country code.  That way you can ask the correct question.

      If all else fails, and it shouldn’t, then you can make some custom changes to the code. (BADI, user exit, or enhancement point)  But I would really discourage you from doing that until you’ve tried all other options.

      Best of luck!



  • Thanks Michelle  for the detailed information on BRF+.

    I wanted to know if is it possible to have editable Email body for the outputs which we setup using BRF+ so that a note is added by user. Currently user is using Medium 7 to send mails to multiple recipients  and also adding a note to the email.  Using BRF+ we can send mails to multiple recipients. But is it possible to add email body every time a mail is sent?

  • Hi Michelle,

    Excellent document.  Appreciate the effort and sharing the document.

    I have a question about how to enable “Messages” tab at a PO without hitting Save.  Is it possible to do this without ABAP code?

    Thank you,

    Johnson Li