Top Enhancement Spots and BAdIs in SAP TM Every ABAPer Should Know

Top Enhancement Spots and BAdIs in SAP TM Every ABAPer Should Know

Every SAP TM project reaches the same point. The customer wants freight units built differently for one plant, a surcharge calculated from a field that standard does not know, or a freight order printout that only goes out when a custom condition is met. The developer searches SE18 and gets a long list of /SCMTMS/ definitions with little documentation.

This post is the short list we wish we had on our first TM project: the enhancement points we actually used, the area each one belongs to, and a pattern that keeps custom code from breaking planning or charge calculation. Names change between TM 9.x and the S/4HANA embedded releases, so treat every object below as a starting point to confirm in SE18 on your own system.

1) How to find the right BAdI yourself

Lists go out of date; a search method does not. We use these four techniques, in this order:

  • SPRO first. TM customizing has a dedicated node for Business Add-Ins under SAP Transportation Management. Each entry there opens the BAdI documentation and the implementation screen. The exact node path differs between releases, so verify it in your release.
  • SE18 / SE84 with a name pattern. In SE84, go to Enhancements > Business Add-Ins > Definitions and search for /SCMTMS/*. Combine this with a keyword such as FUB, TCC (charge calculation) or PLN (planning) to narrow the result.
  • Debugger breakpoint at statement. In the ABAP debugger, set a breakpoint at the statements GET BADI and CALL BADI, then run the business transaction. Every new-style BAdI the process touches will stop the debugger, and you can see the calling class and the data available at that moment.
  • Error messages as clues. Messages such as “Optimizer run canceled in preprocessing BAdI” (message class /SCMTMS/PLN_VSR_IL) tell you that a hook exists at exactly that spot.

2) BAdI or BOPF enhancement? Decide before you code

SAP TM is built on BOPF, so many requirements are better solved with a custom determination, validation or action enhancement on /SCMTMS/TOR or /SCMTMS/TRQ. You create these in the BOPF Enhancement Workbench (transaction /BOBF/CUST_UI). A BAdI is the better choice when SAP has given you a hook inside a process engine, such as planning or charge calculation, where BOPF changes would arrive too early or too late.

Requirement Preferred technique Why
Fill or derive a field on freight order save BOPF determination (enhancement of /SCMTMS/TOR) Runs for every channel: UI, Fiori, background, integration
Block saving when data is inconsistent BOPF validation Messages appear in the standard message log
Add logic before or after a standard action Pre/post action enhancement No modification of the standard action class
Change input or result of the optimizer Planning BAdI Only point where optimizer data is exposed
Custom value for a calculation base Charge calculation BAdI The engine asks for the value at the right moment
Control when output is triggered PPF condition BAdI Output in TM runs through PPF

Pitfall

Do not enhance UI feeder classes to implement business logic. That logic then runs only in that one screen, and background jobs or integration messages skip it.

3) Freight Unit building

Freight Unit building is driven by the FUB rule. Most requirements can be met with conditions in the FUB rule before you write any code. When that is not enough, two hooks are worth knowing:

  • /SCMTMS/TRQ_CHECK_FUB: by default, only changes to standard nodes of /SCMTMS/TRQ trigger freight unit building again. If you added custom nodes to the transportation requirement and changes there must rebuild freight units, this BAdI lets you include them. SAP Knowledge Base Article 2602332 describes this case for TM 9.1 and later.
  • Planning methods FUB_PRE, FUB_POST and FUB_AUTO in class /SCMTMS/CL_PC_METHODS are reported in SAP Community as places to add logic before or after freight unit creation through an enhancement. This is not an official BAdI, so verify in your release that the methods exist and are called in your scenario.

4) Charge calculation

Charge Management has the most useful hooks for consultants, because pricing requirements are where standard most often falls short.

  • /SCMTMS/TCC_BO_DATA_ACCESS, method GET_CALC_BASE_VALUES: use this to supply a value for a calculation base that standard data access cannot read, such as a custom field or a value derived from several nodes. In the calculation base customizing you also have to set the BAdI flag, otherwise the method is never called. We covered the data access side in an earlier post on creating a new calculation base.
  • Charge engine BAdI (interface /SCMTMS/IF_TCC_ENGINE_BADI, method PROCESS_CALCULATION_SHEETS): SAP Community reports this method being called on recalculation and on save, which makes it the place to add or adjust charge lines after the calculation. Verify in your release which BAdI definition implements this interface.
  • Charge calculation rules and formulas: for rate logic that a rate table cannot express, the rule and formula BAdIs are worth checking. Error messages in message class /SCMTMS/TCC_MSG refer to BAdI /SCMTMS/CHARGE_CALCULATION. Verify its methods in SE18 before you design around it.

Pitfall

Calculation base BAdIs run for every charge line of every document. Avoid single SELECTs inside loops. Buffer master data per call, and test with the charge calculation log turned on.

5) Planning and the optimizer

/SCMTMS/PLN_OPT is the BAdI for VSR optimization. It has one method that changes the data sent to the optimizer and one that changes the result before TM applies it. SAP has described using it to model via-locations by adding extra distance, duration and cost to the distance data, because the optimizer does not handle via-locations natively. For load planning, SAP documented a separate enhancement spot, /SCMTMS/PLN_OPT_LSO, which is available from TM 9.1 SP01.

Solution tips

  • Change only the data you need. Removing constraints in preprocessing quietly turns an optimal plan into a wrong one.
  • Any unhandled exception cancels the whole optimizer run. Users then see messages /SCMTMS/PLN_VSR_IL010 or 011 without knowing why.

6) Output management (PPF)

TM output runs through the Post Processing Framework. You maintain the action profiles in SPPFCADM, and TM uses /BOFU/CL_PPF_CONTAINER as the PPF object type. The hooks are standard PPF BAdIs, not TM-specific ones:

  • EVAL_STARTCOND_PPF and EVAL_SCHEDCOND_PPF: start and schedule conditions, for example “print only when the carrier has confirmed”.
  • COMPLETE_PROC_PPF: complete processing data at runtime, for example to set email recipients from the business partner.

Standard ships no conditions, so if output fires too often, check first whether any condition is assigned at all.

7) Integration with ERP / S/4HANA order processing

On the sending side, SD and MM provide BAdIs for sales document, purchase order, delivery and sales order scheduling integration with TM. You can use them to change the control key that decides whether a document goes to TM. For purchase orders the BAdI is BADI_LO_TM_PUR. On the TM side, /SCMTMS/BADI_LI_BTD_CHG (for example method ADAPT_LI_INPUT_MM) adjusts the incoming data. One caveat: an SAP KBA documents that in S/4HANA 2021 and later this method cannot change the PO control key. Do not plan a “skip integration per document” design around it. Use the sending-side BAdI instead.

8) A safe implementation pattern

Whatever the hook, we wrap every TM BAdI implementation the same way: a kill switch, a separate logic class, and no unhandled exceptions. If the custom logic fails, the standard process must still finish.

METHOD <badi_interface>~<method>.
  " 1) Kill switch: deactivate in production without a transport
  SELECT SINGLE low FROM tvarvc
    WHERE name = 'ZTM_BADI_FUB_CHECK' AND type = 'P'
    INTO @DATA(lv_active).
  IF lv_active <> abap_true.
    RETURN.
  ENDIF.

  " 2) Logic lives in its own class: unit-testable, reusable
  TRY.
      NEW zcl_tm_fub_rules( )->evaluate( ... ).
    CATCH cx_root INTO DATA(lx_error).
      " 3) Never dump inside planning or charge calculation:
      "    log the error and let standard continue
      zcl_tm_app_log=>add_exception( lx_error ).
  ENDTRY.
ENDMETHOD.

When the logic needs freight order data, read it through the BOPF service manager (/bobf/cl_tra_serv_mgr_factory=>get_service_manager( /scmtms/if_tor_c=>sc_bo_key )), not with direct SELECTs on the database tables. That way you also see unsaved changes. Never call COMMIT WORK inside a BAdI. The surrounding transaction owns the commit. For larger kill-switch logic, a BRF+ decision table is a cleaner option than TVARVC, as described in our earlier post.

Takeaways

  • Learn to find hooks with SE84, the SPRO BAdI node and a GET BADI breakpoint. That outlasts any list.
  • Prefer BOPF determinations, validations and action enhancements for document logic. Use BAdIs where a process engine (FUB, charges, optimizer, PPF, integration) gives you one.
  • Wrap every implementation with a kill switch and exception handling so custom code can never stop planning or settlement.
  • Confirm every name in SE18 on your own release before you design around it.

Which TM BAdI saved your project, or let you down? Share it in the comments.

Leave a Reply

Your email address will not be published. Required fields are marked *