SAP系统中有很多BOM的打开方式,平铺、多级以及反查的方式多以结构的形式[在前面关于物料清单中也提到过https://blog.csdn.net/qq_55841727/article/details/145442562?fromshare=blogdetail&sharetype=blogdetail&sharerId=145442562&sharerefer=PC&sharesource=qq_55841727&sharefrom=from_link]。SAP 4HANA里面有一个以树状打开的功能BOM浏览器:CSMB

边上小按钮的堆栈可以查看到历史查询的BOM物料,进入结构以后可以看到树状的分布,每一阶层都可以打开(参数要输入完整)。右击可以更方便快捷的展开或者收起,也能跳转到cs11。


值得注意的是:这里自带的打印保存下来的PDF是最后你展开的状态,并不能保存到层次结构到本地。
那想要从系统中保存可展开可复制的树状结构呢
可以通过要使用BOM多级展开函数 CS_BOM_EXPL_MAT_V2,该函数按物料+工厂+用途+有效期等条件,展开标准物料 BOM,可单层/多层,返回组件明细,是 PP / CO / 报表开发里最常用的 BOM 展开入口:
CALL FUNCTION 'CS_BOM_EXPL_MAT_V2'
EXPORTING
capid = 'PP01' "bom类型
datuv = sy-datum "datua "有效期
mdmps = '' " 限制字段:限制BOM只展1层,但下层是虚拟件的则再往下展开一层,默认为空不限制
mehrs = '' " 重要字段:BOM多级展开,默认为空,只展开一层 多阶展开 'X'-多阶; ''-单阶
mtnrv = mtnrv " 必须字段:物料号
werks = werks " 必须字段:工厂号
stlal = '01' "ls_mast-stlal
emeng = 1
stpst = 0
* importing
* topmat = ls_topmat
* DSTST =
TABLES
stb = lt_stpox " 必须接收的表:BOM展开明细
* matcat = lt_matcat " 父级物料清单:参与BOM展开的父级物料清单,即含有组件的物料
EXCEPTIONS
alt_not_found = 1
call_invalid = 2
material_not_found = 3
missing_authorization = 4
no_bom_found = 5
no_plant_data = 6
no_suitable_bom_found = 7
conversion_error = 8
OTHERS = 9.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
调用后,该BOM展开明细会存储到内表中,再对数据的进一步处理。
- mdmps 限制字段:限制BOM只展1层,但下层是虚拟件的则再往下展开一层,默认为空不限制。
- mehrs 重要字段:BOM多级展开,默认为空,只展开一层 多阶展开 'X'-多阶; ' '-单阶。
- stpox这个结构是 把 STPO 的字段和一些附加信息(如层级、路径、计算数量、价格等)打包在一起,方便使用。
首先在ALV显示界面显示树状结构,初始化 ALV 树控件,设置其外观和功能(包括标准按钮和自定义按钮),绑定事件处理类,最后将树展示在屏幕上。
总初始化与调用如下:
form frm_salv_tree .
*1. 容器懒加载:只有当容器未被创建时才执行,防止屏幕多次刷新导致重复创建报错
if gr_container is not bound.
if cl_salv_tree=>is_offline( ) eq if_salv_c_bool_sap=>false.
create object gr_container
exporting
container_name = 'TREE1'. "在屏幕上创建一个自定义容器,容器名称为 TREE1
endif.
*2.创建 ALV 树实例
try.
cl_salv_tree=>factory(
exporting
r_container = gr_container
importing
r_salv_tree = gr_tree
changing
t_table = gt_stpo_alv ).
catch cx_salv_no_new_data_allowed cX_SALV_ERROR.
exit.
endtry.
*3. 构建树形层级关系(调用后面的 Form)
perform create_tree. "注意:对于树形 ALV,上面实例传入的内表通常是扁平结构的数据,真正的层级关系是在 create_tree 中通过设置节点父子关系建立的
data: lr_functions type ref to cl_salv_functions_tree,
l_text type string,
l_icon type string.
lr_functions = gr_tree->get_functions( ).
lr_functions->set_all( 'X' ).
data: lr_columns type ref to cl_salv_columns_tree.
lr_columns = gr_tree->get_columns( ).
lr_columns->set_optimize( if_salv_c_bool_sap=>true )."列宽自适应
*4.设置布局属性
gr_tree->get_tree_settings( )->set_hierarchy_size_in_pixel( if_salv_c_bool_sap=>true ).
perform set_columns_technical using lr_columns. "注意 这个调用的FORM主要控制字段对应列的显示和格式(这里不细展开了)
*5.自定义按钮,导出可触发用户事件
try.
l_text = 'Excel导出'.
l_icon = icon_xls.
lr_functions->add_function(
name = 'EXPORT'
icon = l_icon
text = l_text
tooltip = l_text
position = if_salv_c_function_position=>right_of_salv_functions )." 放在标准按钮右侧
catch cx_salv_wrong_call cx_salv_existing.
endtry.
gr_tree->set_screen_status(
pfstatus = 'ZPPGS9000' "设置 GUI
report = sy-repid
set_functions = gr_tree->c_functions_all ).
*6.注册事件处理
data: lr_events type ref to cl_salv_events_tree.
lr_events = gr_tree->get_event( ).
create object gr_events.
" 绑定各种事件到 gr_events 类的对应方法上
set handler gr_events->on_user_command for lr_events.
set handler gr_events->on_before_salv_function for lr_events.
set handler gr_events->on_after_salv_function for lr_events.
set handler gr_events->on_double_click for lr_events.
set handler gr_events->on_link_click for lr_events.
*7.将构建好的 ALV 树显示在屏幕上
gr_tree->display( ).
endif.
endform.
要将前面从BOM关联的数据表中将扁平的数据组装成父子节点:
form create_tree .
perform frm_build_header. " 设置表头
perform frm_add_nodes. " 添加节点
endform.
form frm_build_header .
data: settings type ref to cl_salv_tree_settings.
settings = gr_tree->get_tree_settings( ).
" 设置左侧树形层级列的标题
settings->set_hierarchy_header( 'BOM层次/备选物料清单' ).
" 设置鼠标悬停提示
settings->set_hierarchy_tooltip( 'ToolTip' ).
" 设置层级列的宽度
settings->set_hierarchy_size( 40 ).
" 获取当前程序的标题,并设置为整个 ALV 树的顶部大标题
data: title type salv_de_tree_text.
title = sy-title.
settings->set_header( title ).
endform.
form frm_add_nodes .
" l1~l10 相当于10个书签,分别记录最近一次遍历到的 1~10 层节点的 KEY
data: l1 type lvc_nkey,l2 type lvc_nkey,l3 type lvc_nkey,l4 type lvc_nkey,
l5 type lvc_nkey,l6 type lvc_nkey,l7 type lvc_nkey,l8 type lvc_nkey,
l9 type lvc_nkey,l10 type lvc_nkey,
l_key type lvc_nkey, " 当前节点的父节点 KEY
l_last_key type lvc_nkey. " 新创建的节点自身的 KEY
loop at gt_stb into data(gs_stb).
" 根据当前行的层级,决定它的父节点是谁
case gs_stb-stufe .
when '0'. l_key = ''. " 0层是顶层,没有父亲
when '1'. l_key = l1. " 1层的父亲是上次记录的0层书签(l1)
when '2'. l_key = l2. " 2层的父亲是上次记录的1层书签(l2)
" ... 依此类推
endcase.
" 调用 Form 在树上创建该节点
perform frm_add_complete_line using gs_stb l_key changing l_last_key.
" 把刚刚创建的节点 KEY 记录到对应层级的书签中
case gs_stb-stufe .
when '0'. l1 = l_last_key. " 如果刚创建的是0层,把它的KEY存入l1,以后1层找爸爸就用它
when '1'. l2 = l_last_key. " 如果刚创建的是1层,把它的KEY存入l2,以后2层找爸爸就用它
" ... 依此类推
endcase.
modify gt_stb from gs_stb .
endloop.
endform.
form frm_add_complete_line using ps_data structure gs_alv p_relat_key changing p_l_last_key.
data: nodes type ref to cl_salv_nodes,
node type ref to cl_salv_node.
data: lv_idnrk type stpox-idnrk.
data: l_node_text type lvc_value.
nodes = gr_tree->get_nodes( ).
" 去除前导零
call function 'CONVERSION_EXIT_MATN1_OUTPUT'
exporting input = ps_data-idnrk
importing output = lv_idnrk.
l_node_text = lv_idnrk.
condense l_node_text no-gaps. " 去除空格
try.
" 核心:添加节点到 ALV 树
node = nodes->add_node(
related_node = p_relat_key " 指定父节点
data_row = ps_data " 绑定该行的内表数据(用于右侧列显示)
text = l_node_text " 显示在左侧树形结构上的文本(物料号)
relationship = cl_gui_column_tree=>relat_last_child ). " 挂载为父节点的最后一个子节点
" 获取系统分配给这个新节点的唯一 KEY,返回给外层做"书签"
p_l_last_key = node->get_key( ).
catch cx_salv_msg.
endtry.
endform.
导出excel到本地:
form show_function_info using i_function type salv_de_function.
case i_function.
when 'EXPORT'. "
perform frm_export_data.
when others.
endcase.
endform.
form frm_export_data .
" 调用自定义的 Excel 模板导出函数
call function 'ZXLWB_CALLFORM'
exporting
iv_formname = 'Z_BOM_TREE' " 指定在 SMW0 中上传的 Excel 模板名称
iv_context_ref = gr_tree " 传入了整个 ALV 树对象!
exceptions
process_terminated = 1
others = 2.
if sy-subrc <> 0.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 raising process_terminated .
endif.
endform.
最后ALV显示结果:

excel表导出结果:
