on 2025 Sep 08 4:29 PM
Hello,
for a dynamic split of a delivery note into more than one freight unit, not based on static criteria like "split every 20 tons" but considering the planning result of the external TMS optimization, I found BADI "/SCMTMS/FUB_CORE" which might solve this requirement, however, I didn't find any kind of documentation or sample coding on how to use it.
The goal would be like:
For the next delivery note having 60tons, the requirement for splitting could be 20-21-19 tons, that's the reason why splitting via FUBR doesn't work.
It's possible to manually split a FU using the Fiori app, however, the split mentioned above based on dynamic criteria should happen when creating/saving the delivery note already.
I've checked the TM extension guide as well, however, didn't find a hint.
Any ideas?
Thanks & regards
Wolfgang
Request clarification before answering.
" Class implementation for BADI /SCMTMS/FUB_CORE
CLASS zcl_tms_dynamic_fu_split DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES /scmtms/if_fub_core.
PRIVATE SECTION.
METHODS:
" Main method to handle dynamic splitting
split_fu_based_on_optimization
IMPORTING
it_fu_root TYPE /scmtms/t_tor_root_k
it_fu_item TYPE /scmtms/t_tor_item_tr_k
CHANGING
ct_fu_root TYPE /scmtms/t_tor_root_k
ct_fu_item TYPE /scmtms/t_tor_item_tr_k
ct_fu_stop TYPE /scmtms/t_tor_stop_k
ct_fu_stop_seq TYPE /scmtms/t_tor_stop_seq_k,
" Get optimization data from external TMS
get_optimization_data
IMPORTING
iv_delivery_number TYPE vbeln
RETURNING
VALUE(rt_opt_data) TYPE ztt_tms_optimization_data,
" Create FU items with split quantities
create_split_fu_items
IMPORTING
is_original_item TYPE /scmtms/s_tor_item_tr_k
it_optimization TYPE ztt_tms_optimization_data
CHANGING
ct_fu_root TYPE /scmtms/t_tor_root_k
ct_fu_item TYPE /scmtms/t_tor_item_tr_k
ct_fu_stop TYPE /scmtms/t_tor_stop_k
ct_fu_stop_seq TYPE /scmtms/t_tor_stop_seq_k.
ENDCLASS.
CLASS zcl_tms_dynamic_fu_split IMPLEMENTATION.
METHOD /scmtms/if_fub_core~prepare_fub.
" Only process if we have FU items to potentially split
IF it_fu_item IS NOT INITIAL.
split_fu_based_on_optimization(
EXPORTING
it_fu_root = it_fu_root
it_fu_item = it_fu_item
CHANGING
ct_fu_root = ct_fu_root
ct_fu_item = ct_fu_item
ct_fu_stop = ct_fu_stop
ct_fu_stop_seq = ct_fu_stop_seq
).
ENDIF.
ENDMETHOD.
METHOD split_fu_based_on_optimization.
DATA:
lt_optimization_data TYPE ztt_tms_optimization_data,
lv_delivery_number TYPE vbeln.
" Group items by delivery note
DATA(lt_items_by_delivery) = VALUE /scmtms/t_tor_item_tr_k(
FOR GROUPS <group> OF <item> IN it_fu_item
GROUP BY <item>-base_btd_tco WITHOUT MEMBERS ( <item> ) ).
LOOP AT lt_items_by_delivery ASSIGNING FIELD-SYMBOL(<ls_item_group>).
" Extract delivery number from reference
lv_delivery_number = <ls_item_group>-base_btd_id.
" Get optimization data from external TMS
lt_optimization_data = get_optimization_data( lv_delivery_number ).
" Only proceed if we have optimization data
IF lt_optimization_data IS NOT INITIAL.
" Process each item in this delivery
LOOP AT it_fu_item ASSIGNING FIELD-SYMBOL(<ls_original_item>)
WHERE base_btd_id = lv_delivery_number.
" Create split FU items based on optimization data
create_split_fu_items(
EXPORTING
is_original_item = <ls_original_item>
it_optimization = lt_optimization_data
CHANGING
ct_fu_root = ct_fu_root
ct_fu_item = ct_fu_item
ct_fu_stop = ct_fu_stop
ct_fu_stop_seq = ct_fu_stop_seq
).
ENDLOOP.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD get_optimization_data.
" This method would interface with your external TMS
" For demonstration, we'll use a mock implementation
" In a real scenario, you would call the TMS API or read from a custom table
" that stores the optimization results by delivery number
" Mock data for testing - replace with actual TMS integration
CASE iv_delivery_number.
WHEN '80000001'. " First delivery note with 60 tons
rt_opt_data = VALUE #(
( sequence = 1 optimal_quantity = 25 unit = 'TON' )
( sequence = 2 optimal_quantity = 20 unit = 'TON' )
( sequence = 3 optimal_quantity = 15 unit = 'TON' )
).
WHEN '80000002'. " Second delivery note with 60 tons
rt_opt_data = VALUE #(
( sequence = 1 optimal_quantity = 20 unit = 'TON' )
( sequence = 2 optimal_quantity = 21 unit = 'TON' )
( sequence = 3 optimal_quantity = 19 unit = 'TON' )
).
WHEN OTHERS.
" For other deliveries, return empty to use standard behavior
ENDCASE.
ENDMETHOD.
METHOD create_split_fu_items.
DATA:
lv_fu_count TYPE i,
lv_total_processed TYPE /scmtms/tor_quantity,
lv_remaining_qty TYPE /scmtms/tor_quantity.
" Calculate initial values
lv_fu_count = lines( ct_fu_root ).
lv_remaining_qty = is_original_item-quantity.
" Create a new FU for each optimization entry
LOOP AT it_optimization ASSIGNING FIELD-SYMBOL(<ls_optimization>).
" Check if we've already allocated the full quantity
IF lv_remaining_qty <= 0.
EXIT.
ENDIF.
" Determine quantity for this FU (don't exceed remaining)
DATA(lv_fu_quantity) = nmin( val1 = <ls_optimization>-optimal_quantity
val2 = lv_remaining_qty ).
" Adjust remaining quantity
lv_remaining_qty = lv_remaining_qty - lv_fu_quantity.
lv_fu_count = lv_fu_count + 1.
" Create new FU root entry
DATA(ls_new_fu_root) = VALUE /scmtms/s_tor_root_k(
" Copy most attributes from original FU
node_id = /scmtms/cl_tor_services=>get_new_node_id( )
tor_id = |{ is_original_item-base_btd_id }-{ lv_fu_count }|
tproc = ct_fu_root[ 1 ]-tproc
tor_cat = /scmtms/if_tor_const=>sc_tor_category-freight_unit
" ... copy other relevant attributes
).
APPEND ls_new_fu_root TO ct_fu_root.
" Create new FU item
DATA(ls_new_fu_item) = is_original_item.
ls_new_fu_item-node_id = /scmtms/cl_tor_services=>get_new_node_id( ).
ls_new_fu_item-parent_node_id = ls_new_fu_root-node_id.
ls_new_fu_item-quantity = lv_fu_quantity.
ls_new_fu_item-base_quantity = lv_fu_quantity.
" ... set other item attributes as needed
APPEND ls_new_fu_item TO ct_fu_item.
" Copy stop sequences (simplified - in reality would need more logic)
LOOP AT ct_fu_stop_seq ASSIGNING FIELD-SYMBOL(<ls_stop_seq>)
WHERE parent_node_id = is_original_item-parent_node_id.
DATA(ls_new_stop_seq) = <ls_stop_seq>.
ls_new_stop_seq-node_id = /scmtms/cl_tor_services=>get_new_node_id( ).
ls_new_stop_seq-parent_node_id = ls_new_fu_root-node_id.
APPEND ls_new_stop_seq TO ct_fu_stop_seq.
ENDLOOP.
ENDLOOP.
" Remove the original FU if we created splits
IF lines( it_optimization ) > 0 AND lv_remaining_qty = 0.
" Remove original FU root
DELETE ct_fu_root WHERE node_id = is_original_item-parent_node_id.
" Remove original FU items
DELETE ct_fu_item WHERE parent_node_id = is_original_item-parent_node_id.
" Remove original stop sequences
DELETE ct_fu_stop_seq WHERE parent_node_id = is_original_item-parent_node_id.
ENDIF.
ENDMETHOD.
ENDCLASS.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 8 | |
| 5 | |
| 3 | |
| 2 | |
| 1 | |
| 1 | |
| 1 | |
| 1 | |
| 1 | |
| 1 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.