ABAP语言的动态编程(4) - 综合案例:管理费用明细表

本篇来实现一个综合案例:管理费用明细表。报表在实际项目中,也有一定的参考意义,一方面展示类似的报表,比如管理费用、研发费用等费用的明细,使用业务比较习惯的展示格式;另一方面正好综合运用前面学习的动态编程知识点。

本系列博客的链接:

ABAP语言的动态编程 (1)-CSDN博客

ABAP语言的动态编程(2) - field symbol 的典型用法_filed symbol-CSDN博客

ABAP语言的动态编程(3) - data reference 对象_abap for in a reference table-CSDN博客

本篇的主要要点:

  • 期间费用等类似报表的取数方法
  • 通过 RTTS 实现动态内表
  • 如何删除动态内表的空值
  • 通过 SALV 输出动态内表

本例实现的功能:

选择屏幕:

输出界面:

程序总体逻辑

  • frm_get_data: 获取数据
  • frm_add_dyn_fields:根据成本中心设置动态内表格式
  • frm_process_data: 将数据加工成输出格式所需的格式
  • frm_alv_show: 在 ALV 中显示数据

数据获取

数据比较简单,直接从 FAGLFLEXT 汇总表获取,也可以直接从 ACDOCA 表获取。

form frm_get_data .ranges: lr_racct for faglflext-racct.lr_racct[] = value #( ( sign = 'I' option = 'CP' low = '0080*' ) ).* 从FAGLFLEXT获取数据select rbukrs             "公司代码, racct as saknr    "科目号, rcntr as kostl    "成本中心, hsl01             "1月, hsl02             "2月, hsl03, hsl04, hsl05, hsl06, hsl07, hsl08, hsl09, hsl10, hsl11, hsl12from v_faglflext_viewwhere rbukrs in @s_bukrsand ryear eq @p_ryearand rldnr eq '0L'and rrcty eq '0'and rvers eq '001'and racct in @lr_racctinto table @data(lt_faglflext).* 按照gs_list格式对数据进行合计loop at lt_faglflext into data(ls_faglflext).move-corresponding ls_faglflext to gs_list.collect gs_list into gt_list.clear: ls_faglflext, gs_list.endloop." 获取会计科目描述select distinct saknr from @lt_faglflext as t into table @data(lt_saknr) .select s~saknr,s~txt20from skat as sinner join @lt_saknr as t on s~saknr eq t~saknrwhere s~ktopl eq '1000'and s~spras eq @sy-languinto table @data(lt_skat).sort lt_skat by saknr." 获取成本中心描述select distinct kostl from @lt_faglflext as t into table @data(lt_cntr). " cost centerselect c~kostl, c~ktextfrom cskt as cinner join @lt_cntr as  d  on c~kostl eq d~kostlwhere c~kokrs eq '1000' and c~spras eq @sy-langu and c~datbi ge @sy-datuminto table @gt_cskt.sort gt_cskt by kostl." 将科目描述和成本中心描述填充到gt_listloop at gt_list into gs_list.if line_exists( lt_skat[ saknr = gs_list-saknr ] ).gs_list-txt20 = lt_skat[ saknr = gs_list-saknr ]-txt20.endif.if line_exists( gt_cskt[ kostl = gs_list-kostl ] ).gs_list-ltext = gt_cskt[ kostl = gs_list-kostl ]-ktext.endif.modify gt_list from gs_list.clear gs_list.endloop.
endform.

设置动态内表

输出的格式中,有些字段是确定的,通过 data 语句直接定义。而每一个成本中心都需要增加一个动态列,在程序中动态设定,关键就是构建动态内表的组件 (gt_component, 类型为 cl_abap_structdescr=>component_table

预先定义的部分:

* 用于数据输出
data: begin of gs_output,rbukrs  type faglflext-rbukrs, "公司代码racct   type faglflext-racct,  "科目号txt20   type skat-txt20,       "科目名称hsl_sum type faglflext-hsl12,  "合计end of gs_output.
data gt_output like standard table of gs_output.

程序动态设置的部分:

*--------------------------------------------------------
* 基于有数据发生的成本中心,将成本中心加到输出字段中
*--------------------------------------------------------
form frm_add_dyn_fields .
data: ls_dref type ref to data,lt_dref type ref to data.data: lo_strcut_descr type ref to cl_abap_structdescr,lo_table_descr  type ref to cl_abap_tabledescr.data: lv_index     type string,lv_fieldname type string.data lv_reffield type faglflext-hsl01.free: gt_component.* 基于gs_outputlo_strcut_descr ?= cl_abap_structdescr=>describe_by_data( gs_output ).gt_component = lo_strcut_descr->get_components( ).* 根据成本中心列表增加动态字段loop at gt_cskt into gs_cskt.lv_index = sy-tabix.lv_fieldname = gc_dyn_prefix && lv_index .condense lv_fieldname no-gaps.clear gs_component.gs_component-name = lv_fieldname.gs_component-type = cast #( cl_abap_elemdescr=>describe_by_data( lv_reffield ) ).append gs_component to gt_component.endloop."根据字段目录创建动态结构类型lo_strcut_descr ?= cl_abap_structdescr=>create( p_components = gt_component ).lo_table_descr ?= cl_abap_tabledescr=>create( p_line_type = lo_strcut_descr ).create data lt_dref type handle lo_table_descr.create data ls_dref type handle lo_strcut_descr.assign ls_dref->* to <dyn_wa>.assign lt_dref->* to <dyn_table>.
endform.

程序运行的时候,gt_component 的结构和内容如下 (每一行的关键是 name 和 type):

根据输出格式加工数据

因为程序只是获取单月的数据,而从 FAGLFLEXT 表取数底表格式(每个月 1 列)决定了有可能当月并没有数据,所以代码中增加了删除空行的代码。静态内表删除内表比较简单,而动态内表因为列名是在程序中生成的,所以处理起来相对麻烦一些。

form frm_process_data .data lv_src_fldname type fieldname.data lv_target_fldname type fieldname.data gv_tabix like sy-tabix.lv_src_fldname = 'HSL' && p_rpmax. " 基于选择屏幕的月份condense lv_src_fldname.*-------------------------------------------------------------
* 行转列,同时进行聚合计算
*-------------------------------------------------------------loop at gt_list into gs_list.move-corresponding gs_list to <dyn_wa>." 从1到12月份,获取选择屏幕所在月份的数据assign component lv_src_fldname of structure gs_list to field-symbol(<lfs_source>)." 找到对应成本中心的indexread table gt_cskt transporting no fields with key kostl = gs_list-kostl binary search.if sy-subrc = 0.gv_tabix = sy-tabix.lv_target_fldname = gc_dyn_prefix && gv_tabix.condense lv_target_fldname.  " 对应的动态列名" 找到成本中心对应的字段assign component lv_target_fldname of structure <dyn_wa> to field-symbol(<lfs_target>).<lfs_target> = <lfs_source>." 合计字段assign component 'HSL_SUM' of structure <dyn_wa> to field-symbol(<lfs_sum>).<lfs_sum> = <lfs_source>.endif.collect <dyn_wa> into <dyn_table>.clear:  gs_list, <dyn_wa>.endloop.*-----------------------------------------------------
* 删除空行
*-----------------------------------------------------data lt_component like gt_component.lt_component[] = gt_component[]." 删除不相关行delete lt_component where name = 'RBUKRS'.delete lt_component where name = 'SAKNR'.delete lt_component where name = 'TXT20'.loop at <dyn_table> assigning <dyn_wa>.data(lv_is_empty) = abap_true." lt_component保存了所有gt_output的字段,删除了RBUKRS, SAKNR和TXT20loop at lt_component assigning field-symbol(<ls_comp>).assign component <ls_comp>-name of structure <dyn_wa> to field-symbol(<ls_field>).if <ls_field> is not initial.lv_is_empty = abap_false.exit.endif.endloop.if lv_is_empty = abap_true.delete <dyn_table>.endif.endloop.endform.

ALV 输出

使用 SALV (CL_SALV_TABLE)在 ALV 中显示数据。

form frm_alv_set_style tables t_data type standard table.data ls_program type salv_s_layout_key."结构包含布局变式所属程序名data lv_tabix like sy-tabix.data lv_fieldname type fieldname.ls_program-report = sy-repid.* 实例化SALVcl_salv_table=>factory(importing r_salv_table = gr_alv_tablechanging t_table = t_data[] ).* 设置动态字段的field catalogdata(lr_alv_columns) = gr_alv_table->get_columns( ).loop at gt_cskt into gs_cskt.lv_tabix = sy-tabix.lv_fieldname = gc_dyn_prefix && lv_tabix.condense lv_fieldname no-gaps.perform frm_set_field using lr_alv_columns lv_fieldname gs_cskt-ktext '' ''.clear gs_cskt.endloop.* 设置合计字段的显示perform frm_set_field using lr_alv_columns 'HSL_SUM' '金额合计' '' ''.* 优化列宽lr_alv_columns->set_optimize( 'X' ).* 设置 toolbargr_alv_table->get_functions( )->set_all(  ).* 设置ALV布局data(lr_layout) = gr_alv_table->get_layout( ).lr_layout->set_key( ls_program ).                                "设置布局保存为变式时基于此Keylr_layout->set_save_restriction( cl_salv_layout=>restrict_none )."允许保存布局为变式* 设置条纹显示gr_alv_table->get_display_settings(  )->set_striped_pattern( abap_true ).
endform.

frm_alv_set_style 调用了 frm_set_field:

form frm_set_field  using uo_cols type ref to cl_salv_columns_tablevalue(uv_fieldname)     " 字段名value(uv_text)          " 字段文本value(uv_length)        " 输出宽度value(uv_istechnical).  " 是否隐藏data: lo_col    type ref to cl_salv_column_table,lo_agg    type ref to cl_salv_aggregations,lv_text_s type scrtext_s,lv_text_m type scrtext_m,lv_text_l type scrtext_l.lo_col ?= uo_cols->get_column( uv_fieldname ).* 是否隐藏if not uv_istechnical is initial.lo_col->set_technical( abap_true ). "隐藏endif.* 设置显示字段文本if not uv_text is initial.lv_text_s = uv_text.lv_text_m = uv_text.lv_text_l = uv_text.lo_col->set_short_text( lv_text_s ).lo_col->set_medium_text( lv_text_m ).lo_col->set_long_text( lv_text_l ).endif.* 设置输出宽度if not uv_length is initial.lo_col->set_output_length( uv_length ).endif.lo_col->set_zero(  '' ).
endform.

调用 display() 方式实现输出:

form frm_alv_show  tables   t_data type standard table.perform frm_alv_set_style tables t_data[].gr_alv_table->display( ).
endform.

为了方便阅读,正文给出主要的代码,完整的代码请参考链接。

源码

ABAP动态编程-管理费用明细表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/898306.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Redis】Redis的数据删除(过期)策略,数据淘汰策略。

如果问到&#xff1a;假如Redis的key过期之后&#xff0c;会立即删除吗&#xff1f; 其实就是想问数据删除(过期)策略。 如果面试官问到&#xff1a;如果缓存过多&#xff0c;内存是有限的&#xff0c;内存被占满了怎么办&#xff1f; 其实就是问&#xff1a;数据的淘汰策略。…

Linux配置yum仓库,服务控制,防火墙

一、yum仓库 1.在安装软件时&#xff0c;首先第一步就是要考虑软件的版本的问题&#xff01; 2.软件的安装&#xff1a;最安全可靠的方法就是去软件对应的官网上查看安装手册&#xff08;包括的软件的下载&#xff09; 红帽系软件安装的常见的3种方式 &#xff08;1&#x…

[从零开始学习JAVA] Stream流

前言&#xff1a; 本文我们将学习Stream流&#xff0c;他就像流水线一样&#xff0c;可以对我们要处理的对象进行逐步处理&#xff0c;最终达到我们想要的效果&#xff0c;是JAVA中的一大好帮手&#xff0c;值得我们了解和掌握。&#xff08;通常和lambda 匿名内部类 方法引用相…

设计模式(创建型)-抽象工厂模式

摘要 在软件开发的复杂世界中,设计模式作为解决常见问题的最佳实践方案,一直扮演着至关重要的角色。抽象工厂模式,作为一种强大的创建型设计模式,在处理创建一系列或相关依赖对象的场景时,展现出了独特的优势和灵活性。它通过提供一个创建对象的接口,让开发者能够在不指定…

【JavaEE】-- SpringBoot快速上手

文章目录 1. Maven1.1 什么是Maven1.2 为什么要学Maven1.3 创建一个Maven项目1.4 Maven核心功能1.4.1 项目创建1.4.2 依赖管理1.4.3 Maven Help插件 1.5 Maven仓库1.5.1 本地仓库1.5.2 中央仓库1.5.3 私有服务器&#xff08;私服&#xff09; 1.6 Maven设置国内源1.6.1 配置当前…

TCP/IP 协议精讲-精华总结版本

序言 本文旨在介绍一下TCP/IP涉及得所有基础知识&#xff0c;为大家从宏观上俯瞰TCP/IP提供一个基石&#xff0c;文档属于《TCP/IP图解&#xff08;第五版&#xff09;》的精简版本。 专业术语 缩写 全称 WAN Wide area network广域网 LAN Local area network局域网 TC…

Leetcode 160 Intersection of Two Linked Lists

题意 给定两个链表&#xff0c;找这两个链表第一个公共节点&#xff0c;如果没有返回nullptr 题目链接 https://leetcode.com/problems/intersection-of-two-linked-lists/description/ 题解 两个指针分别从两个链表&#xff08;记录为表A&#xff0c;表B&#xff09;的表…

C语言——结构体、联合、枚举

C语言中自定义类型 结构体结构体变量的创建和初始化结构体传参结构体内存对齐(如何存储) 联合体(共用体)联合体创建和初始化联合体大小(如何存储) 枚举类型枚举类型创建枚举类型初始化枚举的优点(相较于define) 前言 C语言中有内置类型和自定义类型&#xff0c;内置类型就像int…

利用pprof对golang进行性能分析

利用pprof进行性能分析 pprof性能分析的5个方面 一、性能分析的五个核心维度 CPU分析 - 剖析程序的CPU使用情况&#xff0c;定位高耗时函数 内存分析 - 追踪内存分配与泄露&#xff0c;优化内存使用模式 IO分析 - 监控文件/网络IO操作&#xff0c;发现瓶颈资源 Goroutine分…

IntelliJ IDEA 调试技巧指南

在日常开发中&#xff0c;调试是不可或缺的一部分。掌握调试工具的使用可以让我们更高效地定位和解决问题。本文将介绍一些在 IntelliJ IDEA 中常用的调试技巧&#xff0c;希望能帮助你在开发过程中更顺畅地解决问题。 1. 方法断点&#xff1a;快速定位实现类 方法断点可以帮…

gitlab 提交pr

在 GitLab 中&#xff0c;提交合并请求&#xff08;Merge Request, MR&#xff09;的大致流程如下&#xff1a; 1. 创建新分支 如果你还没有创建新的功能分支&#xff0c;可以使用以下命令创建并切换到新分支&#xff1a; git checkout -b feature-branch说明&#xff1a;f…

halcon几何测量(二)计算距离和角度的函数

目录 一、计算两条线之间的夹角二、计算一条直线和水平轴之间的夹角三、计算两个轮廓之间的最小距离四、计算两个轮廓之间的最小距离和对应的点五、计算直线和区域之间的最小和最大距离六、计算点到轮廓线之间的距离七、计算点到直线的距离八、计算点到点的距离九、计算点和区域…

【Linux操作系统——学习笔记二】Linux简单导航命令操作

一、前言 学习Linux&#xff0c;本质上是学习在命令行下熟练使用Linux的各类命令。 命令行&#xff1a;是一种通过输入命令和参数与计算机系统进行交互的方式&#xff0c;可以使用各种字符化命令对系统发出操作指令&#xff0c;打开Linux终端&#xff0c;进入命令行界面。 …

新安装的cursor安装不了插件

我安装的cursor版本0.47.5 直接说解决办法 找到安装路径cursor\resources\app下的product.json 修改https://marketplace.cursorapi.com为https://marketplace.visualstudio.com

算法基础篇(蓝桥杯常考点)

算法基础篇 前言 算法内容还有搜索&#xff0c;数据结构&#xff08;进阶&#xff09;&#xff0c;动态规划和图论 数学那个的话大家也知道比较难&#xff0c;放在最后讲 这期包含的内容可以看目录 模拟那个算法的话就是题说什么写什么&#xff0c;就不再分入目录中了 注意事…

《解锁华为黑科技:MindSpore+鸿蒙深度集成奥秘》

在数字化浪潮汹涌澎湃的当下&#xff0c;人工智能与操作系统的融合已成为推动科技发展的核心驱动力。华为作为科技领域的先锋&#xff0c;其AI开发框架MindSpore与鸿蒙系统的深度集成备受瞩目&#xff0c;开启了智能生态的新篇章。 华为MindSpore&#xff1a;AI框架的创新先锋…

双3060、Ubuntu22.04、cuda12.8安装deepseek 32b-Q8

以下是针对双RTX 3060显卡&#xff08;12GB显存&#xff09;在Ubuntu 22.04系统部署DeepSeek-R1-32b-qwen-distill-q8模型的完整流程&#xff0c;结合最新技术规范与魔塔社区资源&#xff1a; 一、驱动与CUDA环境配置 1. 禁用开源驱动 bash sudo tee /etc/modprobe.d/blackli…

K8S学习之基础三十四:K8S之监控Prometheus部署pod版

使用 Kubernetes Pod 的方式部署 Prometheus 是一种常见的方法&#xff0c;尤其是在容器化和微服务架构中。以下是详细的步骤&#xff1a; 1. 创建命名空间&#xff08;可选&#xff09; 为了方便管理&#xff0c;可以为 Prometheus 创建一个单独的命名空间。 yaml 复制 a…

Linux top 命令详解:从入门到高级用法

Linux top 命令详解&#xff1a;从入门到高级用法 在 Linux 系统中&#xff0c;top 是一个强大的实时监控工具&#xff0c;用于查看系统资源使用情况和进程状态。它可以帮助你快速了解 CPU、内存、负载等信息&#xff0c;是系统管理员和开发者的日常利器。本文将从基本用法开始…

uniapp-x vue 特性

生命周期 在组合式API中&#xff0c;组件可以监听应用和页面的生命周期。但由于应用和页面都有onShow和onHide&#xff0c;导致重名。所以在组合式的组件中监听页面的显示隐藏&#xff0c;改为了onPageShow和onPageHide。 这个和uniapp不一样&#xff0c;uniapp自定义组件无法…