您的订单到报告:日记账分录数据模板
您的订单到报告:日记账分录数据模板
- 建议收集的属性
- 需要跟踪的关键活动
- 实用的数据提取指南
订单到报告:日记账分录属性
| 名称 | 说明 | ||
|---|---|---|---|
| 事件时间 EventTime | 表示日记账分录中某项活动发生时间的时间戳。 | ||
| 说明 事件时间是业务活动执行并记录到系统中的准确日期和时间。每个案例中的每项活动都有自己的时间戳,由此形成按时间排列的事件序列。 此属性对于所有基于时间的流程分析都至关重要,可用于计算周期时间、活动间隔时长和等待时间,并了解工作的时间分布。准确的时间戳是构建可靠流程模型和计算审批周期时间等关键绩效指标的基础。 重要性 事件时间确定了事件的先后顺序,是计算各类时长指标和了解流程时间线的基础。 获取途径 数据来源包括更改凭证日志(CDHDR-UDATE、CDHDR-UTIME)、工作流日志,以及BKPF等表中的创建或录入时间戳(CPUDT、CPUTM)。 示例 2023-10-26T10:05:00Z2023-11-15T14:30:15Z2024-01-20T09:00:45Z | |||
| 日记账分录ID JournalEntryId | 财务日记账分录的唯一标识符,也是流程的主要案例标识符。 | ||
| 说明 日记账分录ID是SAP S/4HANA为每份会计凭证创建时分配的唯一编号。此标识符对于跟踪日记账分录的完整生命周期至关重要,涵盖初始创建或暂存、审批工作流、最终过账,以及可能发生的冲销或清账。 在流程挖掘分析中,此ID用于将所有相关活动关联到同一个案例。按日记账分录ID对事件进行分组后,分析人员可以还原端到端流程路径、衡量周期时间,并识别每笔财务交易的变体或瓶颈。它是构建完整流程视图的基础属性。 重要性 此标识符将所有相关流程步骤关联起来,便于分析每笔日记账分录的端到端处理过程。 获取途径 这是一个复合键,通常由公司代码(BKPF-BUKRS)、凭证编号(BKPF-BELNR)和会计年度(BKPF-GJAHR)拼接而成。 示例 1000-1000000001-20231710-1900000055-20242000-2100003412-2023 | |||
| 活动 ActivityName | 日记账分录流程中特定时点发生的业务活动名称。 | ||
| 说明 活动表示日记账分录生命周期中的具体步骤或事件,例如“日记账分录已创建”“日记账分录已提交审核”或“日记账分录已过账”。这些活动通常根据系统记录的更改日志、状态更新或事务代码确定。 分析活动有助于将流程路径可视化、识别常见路径,并发现偏离标准过程的情况。活动分析也是计算活动频率、步骤间等待时间和一致性检查率等指标的基础。 重要性 活动定义了流程中的各个步骤,便于将流程图可视化并分析工作流模式。 获取途径 数据来源包括抬头表和项目表中的状态字段(例如BKPF-BSTAT)、更改凭证日志(CDHDR/CDPOS)以及工作流日志。 示例 日记账分录已创建日记账分录已暂存日记账分录已提交审核日记账分录已批准日记账分录已过账 | |||
| 公司代码 CompanyCode | 记账日记账分录的公司或法人实体唯一标识。 | ||
| 说明 公司代码是SAP财务管理中的基本组织单位,代表可独立编制财务报表的法人实体。每笔日记账分录都归属于一个特定公司代码。 此属性对于按组织不同部分细分和比较流程表现至关重要。分析人员可按法人实体筛选流程视图、比较不同公司代码的驳回率,或识别特定地区的流程差异。 重要性 支持按组织内不同法人实体或业务单元筛选和比较日记账分录流程。 获取途径 SAP S/4HANA表BKPF中的字段BUKRS(公司代码)。 示例 10001710US01 | |||
| 创建者用户 CreatedByUser | 创建日记账分录的用户ID。 | ||
| 说明 此属性记录发起日记账分录流程、创建初始凭证的用户唯一标识。该用户可能是会计人员、业务用户,也可能是用于自动记账的系统ID。 按创建者分析流程,有助于发现特定用户或团队相关的规律。例如,某些用户的驳回率较高,可能意味着需要培训;也可以据此识别表现出色的员工。这是“用户活动与处理量”仪表板的重要数据。 重要性 将流程活动关联到具体用户,支持绩效分析、工作量平衡和培训需求识别。 获取途径 SAP S/4HANA表BKPF中的字段USNAM(用户名)。 示例 ABROWNCJONESBATCH_USER | |||
| 日记账分录类型 JournalEntryType | 根据业务用途对日记账分录分类,例如资产记账、供应商发票或总账分录。 | ||
| 说明 日记账分录类型在SAP中称为凭证类型,是用于对会计凭证分类的关键字段。它会控制凭证的编号范围,以及允许记账的科目类型等内容。 按日记账分录类型分析流程,有助于了解不同业务场景下的流程差异。例如,简单应计项目(类型SA)的审批流程可能远比复杂的资产购置(类型AA)简单。此维度是“按分录类型查看合规情况”仪表板的关键。 重要性 按业务场景对分录分类,支持分析不同财务交易类型的流程差异和表现。 获取途径 SAP S/4HANA表BKPF中的字段BLART(凭证类型)。 示例 SAKRAA | |||
| 本币金额 AmountInLocalCurrency | 以公司代码本币表示的日记账分录总金额。 | ||
| 说明 此属性表示日记账分录的财务金额,通常是凭证中所有借方或贷方行项目绝对值之和,并换算为公司代码的本币。 按金额分析,可根据财务影响对流程进行细分。例如,高金额分录可能需要比低金额分录更严格的审批。这样有助于优先改进财务风险最高的交易流程。 重要性 提供分录的财务金额,支持分析流程行为如何随涉及金额而变化。 获取途径 对行项目表BSEG中指定日记账分录(BELNR)的金额(字段DMBTR)求和,并转换为正值。 示例 1500.75125000.0050.20 | |||
| 过账日期 PostingDate | 日记账分录记入总账的日期,会影响所属财务期间。 | ||
| 说明 过账日期决定交易计入财务报表的财务期间,是会计处理中的关键日期,可能与凭证创建日期或录入系统的日期不同。 在流程挖掘中,过账日期可用于按时间划分群组,例如比较月末结账流程,或分析不同财务期间的表现趋势。它也可用于衡量分录创建到实际财务过账之间的延迟。 重要性 对于财务分析至关重要,可按月末或年末等特定会计期间分析流程表现。 获取途径 SAP S/4HANA表BKPF中的字段BUDAT(凭证过账日期)。 示例 2023-10-312023-11-012024-02-29 | |||
| 事务代码 TransactionCode | 用于创建或更改日记账分录的SAP事务代码。 | ||
| 说明 事务代码(T-Code)是用于调用SAP特定功能或程序的快捷代码。对于日记账分录,不同的T-Code可表明分录的创建方式,例如手动总账过账使用FB01,暂存使用FV50,系统自动生成的分录则使用相应的自动化代码。 此属性可有效判断活动是由用户手动执行,还是由系统自动完成。它是计算手动过账率KPI和识别自动化机会的关键。 重要性 显示分录的处理方式(例如手动或自动),是自动化分析和了解流程差异的关键。 获取途径 SAP S/4HANA表BKPF中的字段TCODE(事务代码)。 示例 FB01FV50F-02 | |||
| 最近数据更新时间 LastDataUpdate | 表示此记录的数据最近一次从源系统刷新的时间戳。 | ||
| 说明 此属性记录最近一次从源系统提取或更新数据的日期和时间,便于了解所分析数据的新鲜度。 了解最近更新时间有助于判断流程分析数据的时效性,并帮助用户正确解读仪表板和KPI,确认查看的是近实时数据还是之前某个时段的快照。 重要性 显示数据的新鲜度,帮助用户了解流程分析数据的时效性。 获取途径 这是一个元数据属性,通常在数据接入过程中生成并写入每条记录。 示例 2024-03-10T02:00:00Z2024-03-11T02:00:00Z2024-03-12T02:00:00Z | |||
| 冲销原因 ReversalReason | 说明已过账日记账分录被冲销原因的代码。 | ||
| 说明 已过账的日记账分录如有错误,不能直接删除,必须通过新凭证进行冲销。冲销原因代码用于说明采取此操作的原因,例如过账日期或金额错误。 分析冲销原因有助于找出记录到报告流程中错误的根本原因。某种原因频繁出现,可能反映出培训不足或控制失效等系统性问题,需要及时处理,以提升首次处理质量。 重要性 帮助诊断导致冲销的错误根因,为减少返工、提升流程质量提供依据。 获取途径 SAP S/4HANA表BKPF中的字段STGRD(冲销原因)。 示例 010205 | |||
| 凭证状态 DocumentStatus | 日记账分录当前的处理状态,例如暂存、已过账或已清账。 | ||
| 说明 凭证状态表示日记账分录在生命周期中的阶段。例如,“暂存”凭证已保存,但尚未过账到总账;“已过账”凭证则已完成处理。 分析状态有助于了解工作流转情况并识别瓶颈。大量凭证长期处于“暂存”或“待审批”状态,可能表明流程效率低下。凭证状态也是推导流程活动的重要数据来源。 重要性 显示日记账分录所处的生命周期阶段,帮助识别队列和瓶颈。 获取途径 SAP S/4HANA表BKPF中的字段BSTAT(凭证状态)。 示例 VAB | |||
| 审批周期时间 ApprovalCycleTime | 从日记账分录提交审批,到获批或被驳回所经过的时间。 | ||
| 说明 此计算指标专门衡量审批阶段的持续时间,即“日记账已提交审核”活动与后续“日记账分录已批准”或“日记账分录已驳回”活动之间的时间。 此KPI对于识别审批工作流中的瓶颈至关重要。审批周期过长会显著拖慢整体流程。按审批者、公司代码或日记账分录类型分析此指标,可发现需要改进的具体环节。 重要性 单独衡量审批步骤的时长,帮助定位并解决审核和审批工作流中的瓶颈。 获取途径 计算“日记账已提交审核”事件与“日记账分录已批准”或“日记账分录已驳回”事件之间的时间差。 示例 1天2小时4小时25分钟5天0小时 | |||
| 审批者用户 ApproverUser | 批准或驳回日记账分录的用户ID。 | ||
| 说明 此属性用于识别负责审核已提交日记账分录并作出决定的用户。在多级审批工作流中,一笔日记账分录可能需要多位审批者处理。 这些信息对于详细分析审批流程至关重要,可用于衡量不同审批者的工作量、计算个人审批时间,以及识别审批链中的瓶颈。它直接支持“用户活动与处理量”仪表板。 重要性 识别负责审批的人员,支持分析审批工作量、绩效和瓶颈。 获取途径 可从工作流日志(例如SWW_WI2OBJ、SWWLOG)或更改凭证表(CDHDR/CDPOS)获取,方法是追踪执行审批步骤的用户。 示例 DMILLERFWHITEKCHEN | |||
| 是否手动过账 IsManualPosting | 布尔标记,表示日记账分录是否由用户手动过账。 | ||
| 说明 此属性用于识别通过用户手动操作过账的日记账分录,并将其与系统作业或接口自动过账的分录区分开来。通常可根据过账凭证所用的事务代码推导此属性。 此标记用于计算手动过账率KPI,帮助企业跟踪记录到报告流程的自动化进展。筛选手动过账的分录后,分析人员可识别仍需人工处理的具体场景,并评估其自动化潜力。 重要性 区分人工过账和系统自动过账,对于衡量自动化水平和识别自动化机会至关重要。 获取途径 这是根据TransactionCode计算得出的属性。系统会使用预定义的手动事务代码列表(例如“FB01”“F-02”)将此标记设为“true”。 示例 truefalse | |||
| 是否返工 IsRework | 布尔标记,表示日记账分录是否经过返工,例如被驳回后进行更正。 | ||
| 说明 此计算属性用于标记偏离理想路径的日记账分录。如果案例中出现“日记账分录已驳回”或“日记账分录已更正”等活动,通常会将此属性设为true。 此标记可简化流程效率分析,便于快速计算返工率KPI,并直接比较返工与未返工案例的周期时间和成本。识别返工原因是许多流程改进工作的重点。 重要性 标记需要更正或经历额外循环的案例,便于量化流程低效情况并分析根因。 获取途径 这是根据案例活动顺序计算得出的属性。如果存在“日记账分录已驳回”等活动,则标记为“true”。 示例 truefalse | |||
| 源系统 SourceSystem | 标识提取日记账分录数据的源系统。 | ||
| 说明 此属性用于标明日记账分录数据的来源记录系统。对于使用多个ERP实例,或同时运行旧系统和现代系统的企业,这有助于区分数据来源。 分析时,可按不同系统比较流程表现,也可筛选特定来源的数据。这对于数据治理和理解数据背景至关重要。 重要性 说明数据来源。在多系统环境中,这对于准确分析和比较流程至关重要。 获取途径 这通常是在数据提取时添加的静态值,用于标识具体的SAP S/4HANA实例(例如SID或逻辑系统名称)。 示例 S4H_PROD_100ECC_FIN_200S4C_US_EAST | |||
| 结束时间 EndTime | 表示活动完成时间的时间戳。 | ||
| 说明 结束时间表示活动完成的时刻。在许多事件日志中,活动的开始时间和结束时间相同,表示该事件即时发生。对于有明确持续时间的活动,例如用户主动审核文档,此属性则可记录活动时长。 单独记录结束时间,可以更准确地计算活动处理时间和等待时间,并区分任务实际处理的时长与其在队列中闲置的时长。 重要性 支持精确计算活动处理时间,并将实际工作时间与闲置等待时间区分开来。 获取途径 对于原子事件,通常与StartTime相同。对于有持续时间的活动,可从工作流日志中获取,也可根据后续事件计算。 示例 2023-10-26T10:05:00Z2023-11-15T14:45:20Z2024-01-20T09:10:30Z | |||
| 财年 FiscalYear | 日记账分录所属的财年。 | ||
| 说明 财年与公司代码和凭证编号共同构成日记账分录的唯一键,表示凭证所属的财务年度。 在分析中,财年可用于长期趋势分析,并确保案例标识符唯一。比较不同财年的流程指标,有助于发现流程表现随时间的改善或退化。 重要性 这是唯一识别凭证的关键组成部分,也支持按年分析流程表现。 获取途径 SAP S/4HANA表BKPF中的字段GJAHR(财年)。 示例 202320242022 | |||
订单到报告:日记账分录活动
| 活动 | 说明 | ||
|---|---|---|---|
| 日记账分录冲销已处理 | 通过创建一张反向过账的新凭证,冲销此前已过账的日记账分录。此操作用于更正已过账凭证中的错误,是一项明确且可审计的事务。 | ||
| 重要性 冲销表明已过账凭证中存在错误。冲销率偏高,通常意味着审批流程或数据录入质量存在问题。跟踪冲销情况有助于提高首次处理的准确性。 获取途径 冲销是一项明确事件。新冲销凭证的抬头(BKPF)中,“被冲销凭证编号”(STBLG)字段会引用原凭证。新凭证的过账日期即为事件时间。 采集 识别BKPF-STBLG字段有值的凭证。事件时间戳为冲销凭证的过账日期。 事件类型 explicit | |||
| 日记账分录已创建 | 此活动表示在系统中首次创建日记账分录凭证。记录已写入抬头表BKPF,但尚未过账至总账。这是日记账分录生命周期的起点。 | ||
| 重要性 这是流程的主要开始事件。分析从此事件到过账所需的时间,对于衡量整体周期时间和识别初始数据录入延误至关重要。 获取途径 可通过SAP表BKPF中的创建日期(CPUDT)和创建时间(CPUTM)字段,按凭证编号(BELNR)明确记录此事件。 采集 使用BKPF-CPUDT和BKPF-CPUTM作为事件时间戳。 事件类型 explicit | |||
| 日记账分录已批准 | 日记账分录经授权经理最终批准,确认其有效性和准确性。这是凭证过账至总账前的最后一道关口。 | ||
| 重要性 这是审批周期结束时的关键里程碑。到达此步骤所需的时间,是整体流程时长的重要组成部分,也是衡量审批效率的关键指标。 获取途径 可根据显示最终审批步骤的工作流日志或凭证状态变化推断此事件。审批人的用户ID和时间戳可从工作流数据或更改日志中获取。 采集 在工作流日志中识别最终审批步骤的时间戳,或在更改凭证中识别状态变为“已批准”的时间戳。 事件类型 inferred | |||
| 日记账分录已提交审核 | 日记账分录创建者正式提交凭证,启动审核和审批工作流。此活动表示工作从数据录入阶段移交至正式控制流程,并开启审批周期。 | ||
| 重要性 这是审批周期时间的起点。衡量从此时到最终批准或驳回所需的时间,有助于单独识别审核和审批阶段的瓶颈。 获取途径 通常可从与业务对象关联的工作流日志(表SWW_WIHEAD、SWWLOG)中获取此信息,也可根据凭证抬头(BKPF)自定义字段的状态变化进行推断。 采集 工作流项目创建的时间戳,或状态字段变为“已提交”或“审核中”的时间戳。 事件类型 inferred | |||
| 日记账分录已清账 | 日记账分录中的未清项行项目由另一笔过账进行抵销,例如通过付款清偿发票。此活动表示特定行项目已完成对账并结清。 | ||
| 重要性 对于许多日记账分录,尤其是涉及暂记账户或按未清项管理的账户时,此活动代表最终对账步骤。分析从过账到清账所需的时间,有助于衡量对账效率。 获取途径 可通过行项目表(BSEG或ACDOCA视图)推断此事件。项目清账后,该行的清账日期(AUGDT)和清账凭证(AUGBL)字段会填入相应值。 采集 使用行项目的清账日期(BSEG-AUGDT)作为事件时间戳。 事件类型 inferred | |||
| 日记账分录已过账 | 日记账分录正式记入总账,并影响公司的财务报表。此时,凭证成为永久性财务记录。 | ||
| 重要性 这是流程成功的主要里程碑,标志着核心处理周期结束。分析已过账分录的处理量和到达此阶段所需的时间,是流程挖掘的基础指标。 获取途径 这是由BKPF表中的过账日期(BUDAT)明确标记的事件。已过账凭证的凭证状态(BSTAT)为空,可据此与暂存(“V”)或暂留(“D”)凭证区分。 采集 使用过账日期(BKPF-BUDAT)和录入日期(BKPF-CPUDT)为事件添加时间戳。BKPF-BSTAT为空表示凭证已过账。 事件类型 explicit | |||
| 已识别人工过账 | 日记账分录通过人工事务代码过账,而非通过自动接口或批处理作业过账。这不是一个时间事件,而是对过账活动的分类。 | ||
| 重要性 识别人工过账对于自动化工作至关重要。人工过账比例偏高,说明可以通过集成子系统或使用自动过账程序来简化流程。 获取途径 通过分析凭证抬头表(BKPF)中的事务代码(TCODE)字段进行计算。使用已知人工事务代码列表(例如FB01、F-02、FB50)对分录进行分类。 采集 过账时,根据BKPF-TCODE与预定义的人工事务代码列表对事件进行分类。 事件类型 calculated | |||
| 已附加支持性文档 | 用户将一份或多份支持性文档(例如发票或电子表格)附加到日记账分录,以便在审核和审计过程中为财务交易提供证据和背景信息。 | ||
| 重要性 确保在审核前附上文档,对于合规和提高审批效率至关重要。此活动有助于衡量文档政策的执行情况及其对审批周期的影响。 获取途径 通常可通过检查经通用对象服务(GOS)关联的附件创建时间戳来推断此活动。SRGBTBREL表用于关联业务对象(例如BKPF凭证)与附件。 采集 查询GOS附件表(例如SRGBTBREL),查找与BKPF对象的关联,并使用附件创建时间戳。 事件类型 inferred | |||
| 日记账分录已暂存 | 用户保存尚未完成的日记账分录,但不进行过账,以便稍后补充或审核。这是一项明确操作,会创建状态为“暂存”的凭证抬头记录,使凭证保持未过账状态。 | ||
| 重要性 正式提交前,暂存是常见步骤。跟踪暂存状态的持续时间,有助于发现数据补充和准备阶段的延误,了解正式审核与审批流程开始前的情况。 获取途径 在BKPF表中,凭证状态字段(BSTAT)为“V”表示凭证已暂存。事件时间戳为创建日期(CPUDT)。 采集 筛选创建时BKPF-BSTAT = 'V'的凭证。 事件类型 explicit | |||
| 日记账分录已更正 | 日记账分录被驳回或退回修改后,用户对其进行更改。此活动体现了为解决审核中发现的问题、重新提交凭证所需的返工。 | ||
| 重要性 此活动用于量化返工循环。分析更正的频率和持续时间,有助于找出低效环节,并发现培训和流程说明方面的改进机会。 获取途径 可通过跟踪BKPF表中的“最后更改日期”(AEDAT)来推断此活动,前提是该凭证此前处于“已驳回”状态。更改凭证可提供更具体的更改详情。 采集 对于驳回后进行的更改,使用更改凭证抬头中的时间戳(CDHDR-UDATE)。 事件类型 inferred | |||
| 日记账分录已驳回 | 审核人或审批人驳回日记账分录,阻止其过账。凭证通常会退回创建者修改,从而进入返工循环。 | ||
| 重要性 跟踪驳回情况是了解流程质量和发现常见错误的关键。驳回率偏高,通常说明数据准确性、政策理解或支持性文档方面存在问题。 获取途径 可根据工作流日志或日记账分录凭证自定义状态字段的变化推断此事件。相关状态字段的更改凭证日志(CDHDR/CDPOS)可提供时间戳。 采集 通过更改凭证(CDHDR/CDPOS)或工作流日志,识别状态字段变为“已驳回”的记录。 事件类型 inferred | |||
| 日记账分录过账后已更改 | 日记账分录过账至总账后,用户更改其中有限的字段。虽然大部分财务数据在过账后不可更改,但文本或分配等某些字段仍可修改。 | ||
| 重要性 此活动是重要的合规警示。过账后的更改可能意味着有人试图篡改记录,应密切监控,以防止欺诈并确保数据完整性。 获取途径 可通过更改凭证表(CDHDR和CDPOS)可靠地推断此活动。如果CDHDR中存在该凭证编号的记录,且更改日期晚于过账日期,即表示过账后发生了更改。 采集 在CDHDR中查找更改时间戳(UDATE/UTIME)晚于凭证过账日期(BKPF-BUDAT)的记录。 事件类型 inferred | |||
数据提取指南
步骤
- 前提条件与访问权限:确保您使用的用户拥有查询SAP S/4HANA底层数据库或运行ABAP报表所需的授权。您需要对CDS视图I_JournalEntry、I_JournalEntryItem以及表CDHDR、CDPOS、SRGBREL、SOOD、SWW_WI2OBJ和SWWLOGHIST拥有读取权限。通常可通过SAP HANA Studio、DBeaver等数据库客户端,或通过Eclipse的SAP ABAP Development Tools(ADT)访问。
- 确认系统专属配置:运行查询前,先确认日记账分录审批工作流使用的具体任务代码。请联系SAP工作流管理员,查找对应提交、拒绝和批准事件的任务ID(例如TS12345678)。最终查询中的占位符需要填写这些ID。
- 准备SQL查询:将
query部分提供的完整SQL查询复制到您选用的SQL客户端或开发工具中。 - 设置查询参数:找到查询中的占位符,并替换为实际值,包括
[YourCompanyCode]、[StartDate]和[EndDate]。还需将工作流任务ID占位符[Workflow Submitted Task ID]、[Workflow Rejected Task ID]和[Workflow Approved Task ID]替换为上一步确认的值。 - 运行提取查询:在SAP S/4HANA数据库上运行修改后的SQL查询。查询耗时取决于日期范围和数据量,可能需要较长时间。建议在业务低峰时段运行。
- 检查初步结果:查询完成后,检查输出的前几行,确认JournalEntryId、ActivityName和EventTime等列均已按预期填充。结果集应为日记账分录生命周期中的每个不同业务事件各返回一行。
- 将数据导出为CSV:使用SQL工具将完整结果集导出为一个CSV文件。请确保文件采用UTF-8编码,以免特殊字符显示异常。
- 准备上传:上传到流程挖掘工具前,确认CSV文件包含所需的表头。数据已整理为事件日志格式,通常无需进一步转换或透视。
配置
- 核心数据服务(CDS)视图:提取主要使用
I_JournalEntry获取抬头数据,使用I_JournalEntryItem获取行项目和金额详情。这些视图为通用日记账(ACDOCA)提供了简化且语义丰富的访问接口。 - 辅助表:为完整呈现流程,查询还会联接多个SAP标准表:
- 使用
CDHDR和CDPOS跟踪单据变更。 - 使用
SRGBREL和SOOD识别通过通用对象服务(GOS)关联附件的时间。 - 使用
SWW_WI2OBJ和SWWLOGHIST提取审批工作流中的关键事件。
- 使用
- 日期范围筛选:按指定日期范围筛选数据对控制性能至关重要。请在
WHERE子句中使用I_JournalEntry.CreationDateTime字段。初次分析建议选择3至6个月的数据。 - 组织范围筛选:始终按
CompanyCode筛选,将提取范围限制在相关法人实体内。在大型系统中一次查询所有公司代码,可能导致执行时间过长。 - 工作流任务ID:查询中包含工作流任务ID占位符(例如
[Workflow Approved Task ID])。这些ID因SAP部署而异,必须正确配置才能提取工作流活动。若未配置,将无法捕获提交、批准或拒绝事件。 - 前提条件:执行用户需要对财务、系统和工作流表拥有广泛的读取权限。这些权限并非默认配置,必须单独授予。
查询示例 sql
WITH JournalEntryAmountCTE AS (
SELECT
CompanyCode,
AccountingDocument,
FiscalYear,
SUM(AmountInCompanyCodeCurrency) AS AmountInLocalCurrency
FROM I_JournalEntryItem
GROUP BY CompanyCode, AccountingDocument, FiscalYear
),
JournalEntryBaseCTE AS (
SELECT
JE.CompanyCode,
JE.AccountingDocument,
JE.FiscalYear,
JE.CreatedByUser,
JE.CreationDateTime,
JE.PostingDateTime,
JE.PostingDate,
JE.AccountingDocumentType,
JE.DocumentIsParked,
JE.ReversedJournalEntry,
JE.TransactionCode,
JEA.AmountInLocalCurrency
FROM I_JournalEntry AS JE
LEFT JOIN JournalEntryAmountCTE AS JEA
ON JE.CompanyCode = JEA.CompanyCode
AND JE.AccountingDocument = JEA.AccountingDocument
AND JE.FiscalYear = JEA.FiscalYear
WHERE JE.CompanyCode IN ('[YourCompanyCode]')
AND JE.CreationDateTime BETWEEN '[StartDate]' AND '[EndDate]'
)
-- 1. Journal Entry Created
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Created' AS "ActivityName",
BJE.CreationDateTime AS "EventTime",
BJE.CreatedByUser AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
UNION ALL
-- 2. Journal Entry Parked
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Parked' AS "ActivityName",
BJE.CreationDateTime AS "EventTime",
BJE.CreatedByUser AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
WHERE BJE.DocumentIsParked = 'X'
UNION ALL
-- 3. Supporting Documentation Attached
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Supporting Documentation Attached' AS "ActivityName",
TO_TIMESTAMP(SOOD.CREDAT || ' ' || SOOD.CRETIM, 'YYYYMMDD HH24MISS') AS "EventTime",
SOOD.OWNER AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
JOIN SRGBREL ON SRGBREL.INSTID_A = CONCAT(BJE.CompanyCode, BJE.AccountingDocument, BJE.FiscalYear)
AND SRGBREL.TYPEID_A = 'BKPF'
AND SRGBREL.CATID_A = 'BO'
JOIN SOOD ON SOOD.OBJTP = SRGBREL.TYPEID_B
AND SOOD.OBJYR = SRGBREL.INSTID_B(3)
AND SOOD.OBJNO = SRGBREL.INSTID_B(5)
UNION ALL
-- 4. Journal Submitted For Review
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Submitted For Review' AS "ActivityName",
LOG.END_TS AS "EventTime",
LOG.EXEC_USER AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
JOIN SWW_WI2OBJ AS WF_LINK ON WF_LINK.INSTID = CONCAT(BJE.CompanyCode, BJE.AccountingDocument, BJE.FiscalYear)
AND WF_LINK.TYPEID = 'BKPF'
JOIN SWWLOGHIST AS LOG ON LOG.WI_ID = WF_LINK.WI_ID
WHERE LOG.METHOD = '[Workflow Submitted Task ID]'
UNION ALL
-- 5. Journal Entry Rejected
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Rejected' AS "ActivityName",
LOG.END_TS AS "EventTime",
LOG.EXEC_USER AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
JOIN SWW_WI2OBJ AS WF_LINK ON WF_LINK.INSTID = CONCAT(BJE.CompanyCode, BJE.AccountingDocument, BJE.FiscalYear)
AND WF_LINK.TYPEID = 'BKPF'
JOIN SWWLOGHIST AS LOG ON LOG.WI_ID = WF_LINK.WI_ID
WHERE LOG.METHOD = '[Workflow Rejected Task ID]'
UNION ALL
-- 6. Journal Entry Corrected (changed while parked)
SELECT DISTINCT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Corrected' AS "ActivityName",
TO_TIMESTAMP(CH.UDATE || ' ' || CH.UTIME, 'YYYYMMDD HH24MISS') AS "EventTime",
CH.USERNAME AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
JOIN CDHDR AS CH ON CH.OBJECTID = CONCAT(BJE.CompanyCode, BJE.AccountingDocument, BJE.FiscalYear)
AND CH.OBJECTCLASS = 'BELEG'
WHERE BJE.DocumentIsParked = 'X'
UNION ALL
-- 7. Journal Entry Approved
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Approved' AS "ActivityName",
LOG.END_TS AS "EventTime",
LOG.EXEC_USER AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
JOIN SWW_WI2OBJ AS WF_LINK ON WF_LINK.INSTID = CONCAT(BJE.CompanyCode, BJE.AccountingDocument, BJE.FiscalYear)
AND WF_LINK.TYPEID = 'BKPF'
JOIN SWWLOGHIST AS LOG ON LOG.WI_ID = WF_LINK.WI_ID
WHERE LOG.METHOD = '[Workflow Approved Task ID]'
UNION ALL
-- 8. Manual Posting Identified
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Manual Posting Identified' AS "ActivityName",
BJE.PostingDateTime AS "EventTime",
BJE.CreatedByUser AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
WHERE BJE.PostingDateTime IS NOT NULL AND BJE.TransactionCode IN ('FB01', 'F-02', 'FB50', 'FV50', 'FBB1', 'FBV1')
UNION ALL
-- 9. Journal Entry Posted
SELECT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Posted' AS "ActivityName",
BJE.PostingDateTime AS "EventTime",
BJE.CreatedByUser AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
WHERE BJE.PostingDateTime IS NOT NULL
UNION ALL
-- 10. Journal Entry Changed After Posting
SELECT DISTINCT
BJE.AccountingDocument AS "JournalEntryId",
'Journal Entry Changed After Posting' AS "ActivityName",
TO_TIMESTAMP(CH.UDATE || ' ' || CH.UTIME, 'YYYYMMDD HH24MISS') AS "EventTime",
CH.USERNAME AS "CreatedByUser",
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS BJE
JOIN CDHDR AS CH ON CH.OBJECTID = CONCAT(BJE.CompanyCode, BJE.AccountingDocument, BJE.FiscalYear)
AND CH.OBJECTCLASS = 'BELEG'
WHERE BJE.PostingDateTime IS NOT NULL AND TO_TIMESTAMP(CH.UDATE || ' ' || CH.UTIME, 'YYYYMMDD HH24MISS') > BJE.PostingDateTime
UNION ALL
-- 11. Journal Entry Cleared
SELECT
JEI.AccountingDocument AS "JournalEntryId",
'Journal Entry Cleared' AS "ActivityName",
MIN(JEI.ClearingDateTime) AS "EventTime",
BJE.CreatedByUser AS "CreatedByUser", -- Note: Clearing user is not directly available here
BJE.CompanyCode AS "CompanyCode",
BJE.AccountingDocumentType AS "JournalEntryType",
BJE.PostingDate AS "PostingDate",
BJE.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM I_JournalEntryItem AS JEI
JOIN JournalEntryBaseCTE AS BJE ON JEI.AccountingDocument = BJE.AccountingDocument
AND JEI.CompanyCode = BJE.CompanyCode
AND JEI.FiscalYear = BJE.FiscalYear
WHERE JEI.ClearingDateTime IS NOT NULL
GROUP BY JEI.AccountingDocument, BJE.CreatedByUser, BJE.CompanyCode, BJE.AccountingDocumentType, BJE.PostingDate, BJE.AmountInLocalCurrency
UNION ALL
-- 12. Journal Entry Reversal Processed
SELECT
OriginalDoc.AccountingDocument AS "JournalEntryId",
'Journal Entry Reversal Processed' AS "ActivityName",
ReversalDoc.PostingDateTime AS "EventTime",
ReversalDoc.CreatedByUser AS "CreatedByUser",
OriginalDoc.CompanyCode AS "CompanyCode",
OriginalDoc.AccountingDocumentType AS "JournalEntryType",
OriginalDoc.PostingDate AS "PostingDate",
OriginalDoc.AmountInLocalCurrency AS "AmountInLocalCurrency"
FROM JournalEntryBaseCTE AS ReversalDoc
JOIN JournalEntryBaseCTE AS OriginalDoc
ON ReversalDoc.ReversedJournalEntry = OriginalDoc.AccountingDocument
AND ReversalDoc.CompanyCode = OriginalDoc.CompanyCode
AND ReversalDoc.ReversalFiscalYear = OriginalDoc.FiscalYear
WHERE ReversalDoc.ReversedJournalEntry IS NOT NULL; 步骤
- 确认已获准直接访问SAP HANA数据库,并确认提取用户对BKPF和ACDOCA拥有读取权限,以及对系统所需的工作流、附件、变更历史、清账或冲销数据源拥有读取权限。通常使用SAP HANA Database Explorer、SAP HANA Studio或获准的SQL客户端进行数据库直连。除非系统明确支持,否则不要在SAP应用事务中运行提取查询。
- 确认BKPF和ACDOCA的物理架构,包括客户端字段、公司代码字段、会计年度字段、单据编号字段、单据类型字段、过账日期字段、创建日期字段、创建时间字段、用户字段、本币金额字段,以及任何冲销或清账字段。不同SAP S/4HANA部署的架构和字段可能有所不同,请将查询中的方括号占位符替换为已在系统中核实的字段。
- 确认工作流和附件事件的权威数据源。BKPF和ACDOCA提供会计单据及行项目数据,但无法单独可靠地呈现所有暂存、提交、拒绝、更正、批准或附件事件。请将工作流和附件数据源占位符替换为您所在环境中获准使用的视图或表。如果某个数据源不可用,请勿虚构事件。应配置相应数据源,或经记录并获批后排除该活动。
- 设置所需的提取参数,包括日期范围、公司代码、单据类型和客户端。初次验证建议使用3至6个月的数据。根据约定的流程范围,业务事件使用事件时间范围,会计事件使用过账日期范围。
- 在获准的HANA SQL客户端中运行完整SQL查询。查询会为每项明确提取的活动生成一条事件记录。会计事件来自BKPF和ACDOCA;工作流、附件、变更、清账和冲销事件来自已配置的数据源。查询不会仅凭单据存在与否推断活动。
- 检查输出结构。JournalEntryId是案例标识,ActivityName是活动名称,EventTime是事件时间戳;可用时还会返回建议的业务属性。确认EventTime为时间戳,且所有行的JournalEntryId和ActivityName均非空。
- 将不同JournalEntryId的数量与所选客户端、公司代码、会计年度和日期范围内预期的BKPF记录进行比较,以核对会计数据范围。工作流和附件数据应分别核对,因为其保留期限和时间戳规则可能与会计数据不同。
- 验证事件顺序和重复记录处理方式。除非流程设计明确要求按行项目记录事件,否则ACDOCA中的多个行项目不应造成重复的会计事件。使用查询中的聚合逻辑,按每个日记账分录和事件类型生成一条会计事件;如有可用的已配置数据源事件ID,则予以保留。
- 将结果导出为UTF-8编码的CSV文件或其他ProcessMind支持的表格格式。保留列名JournalEntryId、ActivityName和EventTime,并按JournalEntryId和EventTime排序;其他属性保留为列。将文件上传到ProcessMind,并将JournalEntryId设为案例标识、ActivityName设为活动、EventTime设为事件时间戳。
配置
- **日期范围:**从3至6个月的数据开始。性能测试时可缩短范围;验证行数和事件覆盖情况后再扩大范围。
- **客户端和公司范围:**设置[Client parameter],并将CompanyCode限制为所需的法人实体。在多客户端系统中,不要省略客户端筛选条件。
- **会计范围:**配置[Document type filter],并视情况设置会计年度和过账日期筛选条件。只有在所选数据源能可靠呈现未过账单据时,才将其纳入分析。
- **工作流范围:**配置[Workflow event source]及其事件类型映射,以识别已提交、已拒绝、已更正和已批准等活动。确认时间戳代表工作流操作的创建、执行还是完成时间。
- **附件范围:**配置[Attachment event source]以及用于关联附件和日记账分录的关系字段。确认数据源记录的是附件创建、替换还是删除。
- **变更范围:**配置[Change history source]以提取过账后的变更。确认数据源能够识别日记账分录并提供可靠的变更时间戳。
- **清账范围:**配置[Clearing source]以及已清账会计单据与清账单据之间的关系。确定事件应归属于原始日记账分录、清账单据,还是两者。
- **冲销范围:**配置[Reversal source]以及原始单据与冲销单据之间的关系。如果能够获取该关系,查询会将冲销活动归入原始JournalEntryId。
- **手工过账分类:**配置[Manual posting source]或经过核实的过账来源字段。Manual Posting Identified属于分类事件,应统一使用过账时间戳或其他获准的时间戳。
- **货币金额:**ACDOCA按行项目记录数据。查询会按日记账分录汇总本币金额。请确认正负号规则,以及是否应纳入统计、特定分类账或扩展分类账记录。
- **性能:**仅选择所需列,尽早筛选,避免不受限制地扫描ACDOCA,并在获准的报表时段运行。系统支持时,可通过客户端、会计年度、公司代码和过账日期筛选条件裁剪分区。
- **重复记录处理:**尽可能使用数据源事件ID。如果数据源可能包含重复的技术记录,请按已记录的去重规则处理,同时保留实际发生的不同工作流操作。
- **前提条件:**所需的数据库授权、获准的SAP HANA连接、对已配置工作流和附件数据源的访问权限、适当的SAP财务会计及工作流配置,以及ProcessMind支持的导出格式。
查询示例 sql
WITH
accounting_base AS (
SELECT
b.[Client field] AS ClientId,
b.[Company code field] AS CompanyCode,
b.[Fiscal year field] AS FiscalYear,
b.[Document number field] AS AccountingDocumentNumber,
b.[Document type field] AS JournalEntryType,
b.[Created by field] AS CreatedByUser,
b.[Document date field] AS DocumentDate,
b.[Posting date field] AS PostingDate,
b.[Creation date field] AS CreationDate,
b.[Creation time field] AS CreationTime,
b.[Reversal document field] AS ReversalDocumentNumber,
b.[Reversed document field] AS ReversedDocumentNumber,
b.[Reversal fiscal year field] AS ReversalFiscalYear,
SUM(a.[Local currency amount field]) AS AmountInLocalCurrency,
MAX(a.[Local currency field]) AS LocalCurrency
FROM [Your schema].[BKPF] b
INNER JOIN [Your schema].[ACDOCA] a
ON a.[Client field] = b.[Client field]
AND a.[Company code field] = b.[Company code field]
AND a.[Fiscal year field] = b.[Fiscal year field]
AND a.[Document number field] = b.[Document number field]
WHERE b.[Client field] = '[Client parameter]'
AND b.[Company code field] IN ([Company code filter])
AND b.[Posting date field] BETWEEN '[Start date parameter]' AND '[End date parameter]'
AND b.[Document type field] IN ([Document type filter])
GROUP BY
b.[Client field],
b.[Company code field],
b.[Fiscal year field],
b.[Document number field],
b.[Document type field],
b.[Created by field],
b.[Document date field],
b.[Posting date field],
b.[Creation date field],
b.[Creation time field],
b.[Reversal document field],
b.[Reversed document field],
b.[Reversal fiscal year field]
),
base_cases AS (
SELECT
ClientId,
CompanyCode,
FiscalYear,
AccountingDocumentNumber,
CAST(CompanyCode || '/' || FiscalYear || '/' || AccountingDocumentNumber AS NVARCHAR(100)) AS JournalEntryId,
JournalEntryType,
CreatedByUser,
PostingDate,
AmountInLocalCurrency,
LocalCurrency,
CreationDate,
CreationTime,
ReversalDocumentNumber,
ReversedDocumentNumber,
ReversalFiscalYear
FROM accounting_base
),
created_events AS (
SELECT
JournalEntryId,
'Journal Entry Created' AS ActivityName,
CAST(CreationDate || ' ' || CreationTime AS TIMESTAMP) AS EventTime,
CreatedByUser,
CompanyCode,
JournalEntryType,
PostingDate,
AmountInLocalCurrency,
LocalCurrency
FROM base_cases
),
parked_events AS (
SELECT
CAST(w.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Parked' AS ActivityName,
CAST(w.[Event timestamp field] AS TIMESTAMP) AS EventTime,
w.[User field] AS CreatedByUser,
w.[Company code field] AS CompanyCode,
w.[Journal entry type field] AS JournalEntryType,
w.[Posting date field] AS PostingDate,
w.[Amount in local currency field] AS AmountInLocalCurrency,
w.[Local currency field] AS LocalCurrency
FROM [Your schema].[Workflow event source] w
WHERE w.[Client field] = '[Client parameter]'
AND w.[Event type field] = '[Parked event type]'
AND CAST(w.[Event timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
attachment_events AS (
SELECT
CAST(x.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Supporting Documentation Attached' AS ActivityName,
CAST(x.[Event timestamp field] AS TIMESTAMP) AS EventTime,
x.[User field] AS CreatedByUser,
x.[Company code field] AS CompanyCode,
x.[Journal entry type field] AS JournalEntryType,
x.[Posting date field] AS PostingDate,
x.[Amount in local currency field] AS AmountInLocalCurrency,
x.[Local currency field] AS LocalCurrency
FROM [Your schema].[Attachment event source] x
WHERE x.[Client field] = '[Client parameter]'
AND x.[Event type field] = '[Attachment created event type]'
AND CAST(x.[Event timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
submitted_events AS (
SELECT
CAST(w.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Submitted For Review' AS ActivityName,
CAST(w.[Event timestamp field] AS TIMESTAMP) AS EventTime,
w.[User field] AS CreatedByUser,
w.[Company code field] AS CompanyCode,
w.[Journal entry type field] AS JournalEntryType,
w.[Posting date field] AS PostingDate,
w.[Amount in local currency field] AS AmountInLocalCurrency,
w.[Local currency field] AS LocalCurrency
FROM [Your schema].[Workflow event source] w
WHERE w.[Client field] = '[Client parameter]'
AND w.[Event type field] = '[Submitted event type]'
AND CAST(w.[Event timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
rejected_events AS (
SELECT
CAST(w.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Rejected' AS ActivityName,
CAST(w.[Event timestamp field] AS TIMESTAMP) AS EventTime,
w.[User field] AS CreatedByUser,
w.[Company code field] AS CompanyCode,
w.[Journal entry type field] AS JournalEntryType,
w.[Posting date field] AS PostingDate,
w.[Amount in local currency field] AS AmountInLocalCurrency,
w.[Local currency field] AS LocalCurrency
FROM [Your schema].[Workflow event source] w
WHERE w.[Client field] = '[Client parameter]'
AND w.[Event type field] = '[Rejected event type]'
AND CAST(w.[Event timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
corrected_events AS (
SELECT
CAST(w.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Corrected' AS ActivityName,
CAST(w.[Event timestamp field] AS TIMESTAMP) AS EventTime,
w.[User field] AS CreatedByUser,
w.[Company code field] AS CompanyCode,
w.[Journal entry type field] AS JournalEntryType,
w.[Posting date field] AS PostingDate,
w.[Amount in local currency field] AS AmountInLocalCurrency,
w.[Local currency field] AS LocalCurrency
FROM [Your schema].[Workflow event source] w
WHERE w.[Client field] = '[Client parameter]'
AND w.[Event type field] = '[Corrected event type]'
AND CAST(w.[Event timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
approved_events AS (
SELECT
CAST(w.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Approved' AS ActivityName,
CAST(w.[Event timestamp field] AS TIMESTAMP) AS EventTime,
w.[User field] AS CreatedByUser,
w.[Company code field] AS CompanyCode,
w.[Journal entry type field] AS JournalEntryType,
w.[Posting date field] AS PostingDate,
w.[Amount in local currency field] AS AmountInLocalCurrency,
w.[Local currency field] AS LocalCurrency
FROM [Your schema].[Workflow event source] w
WHERE w.[Client field] = '[Client parameter]'
AND w.[Event type field] = '[Approved event type]'
AND CAST(w.[Event timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
manual_events AS (
SELECT
JournalEntryId,
'Manual Posting Identified' AS ActivityName,
CAST(PostingDate AS TIMESTAMP) AS EventTime,
CreatedByUser,
CompanyCode,
JournalEntryType,
PostingDate,
AmountInLocalCurrency,
LocalCurrency
FROM base_cases
WHERE [Manual posting condition verified for this system]
),
posted_events AS (
SELECT
JournalEntryId,
'Journal Entry Posted' AS ActivityName,
CAST(PostingDate AS TIMESTAMP) AS EventTime,
CreatedByUser,
CompanyCode,
JournalEntryType,
PostingDate,
AmountInLocalCurrency,
LocalCurrency
FROM base_cases
WHERE [Posted document condition verified for this system]
),
changed_events AS (
SELECT
CAST(c.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Changed After Posting' AS ActivityName,
CAST(c.[Change timestamp field] AS TIMESTAMP) AS EventTime,
c.[User field] AS CreatedByUser,
c.[Company code field] AS CompanyCode,
c.[Journal entry type field] AS JournalEntryType,
c.[Posting date field] AS PostingDate,
c.[Amount in local currency field] AS AmountInLocalCurrency,
c.[Local currency field] AS LocalCurrency
FROM [Your schema].[Change history source] c
WHERE c.[Client field] = '[Client parameter]'
AND c.[Post posting change indicator field] = '[Post posting change value]'
AND CAST(c.[Change timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
cleared_events AS (
SELECT
CAST(cl.[Journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Cleared' AS ActivityName,
CAST(cl.[Clearing timestamp field] AS TIMESTAMP) AS EventTime,
cl.[User field] AS CreatedByUser,
cl.[Company code field] AS CompanyCode,
cl.[Journal entry type field] AS JournalEntryType,
cl.[Posting date field] AS PostingDate,
cl.[Amount in local currency field] AS AmountInLocalCurrency,
cl.[Local currency field] AS LocalCurrency
FROM [Your schema].[Clearing source] cl
WHERE cl.[Client field] = '[Client parameter]'
AND CAST(cl.[Clearing timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
),
reversal_events AS (
SELECT
CAST(r.[Original journal entry ID field] AS NVARCHAR(100)) AS JournalEntryId,
'Journal Entry Reversal Processed' AS ActivityName,
CAST(r.[Reversal timestamp field] AS TIMESTAMP) AS EventTime,
r.[User field] AS CreatedByUser,
r.[Company code field] AS CompanyCode,
r.[Journal entry type field] AS JournalEntryType,
r.[Posting date field] AS PostingDate,
r.[Amount in local currency field] AS AmountInLocalCurrency,
r.[Local currency field] AS LocalCurrency
FROM [Your schema].[Reversal source] r
WHERE r.[Client field] = '[Client parameter]'
AND CAST(r.[Reversal timestamp field] AS DATE) BETWEEN '[Start date parameter]' AND '[End date parameter]'
)
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM created_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM parked_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM attachment_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM submitted_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM rejected_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM corrected_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM approved_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM manual_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM posted_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM changed_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM cleared_events
UNION ALL
SELECT JournalEntryId, ActivityName, EventTime, CreatedByUser, CompanyCode, JournalEntryType, PostingDate, AmountInLocalCurrency, LocalCurrency FROM reversal_events
ORDER BY JournalEntryId, EventTime, ActivityName; 步骤
- 创建ABAP程序:使用事务代码
SE38打开ABAP编辑器。输入新程序名称,例如Z_PM_JE_EXTRACT,然后点击“创建”。填写合适的标题,将“类型”设为“可执行程序”,并保存为本地对象或保存在程序包中。 - 定义选择屏幕:在程序中定义参数和选择选项,以便用户筛选数据。应包括日记账分录创建日期范围(
P_CPUDT_FR、P_CPUDT_TO)、公司代码选择选项(SO_BUKRS),以及应用服务器上的输出文件路径(P_FPATH)。 - 声明数据结构:定义与所需事件日志格式一致的内表结构,用于存放最终输出。同时,为要读取的SAP表声明内表和工作区,例如BKPF、ACDOCA、CDHDR、CDPOS及各类工作流表。
- 编写数据选择逻辑:编写ABAP核心逻辑,提取12项所需活动的数据。为每项活动分别创建子例程(FORM),使代码结构清晰。例如,可创建
get_created_events、get_parked_events和get_workflow_events等FORM。 - 选择“已创建”和“已过账”事件:根据用户在选择屏幕中设置的条件读取BKPF表。BKPF中的记录表示单据已创建。状态为
BSTAT = ' '的单据视为已过账。使用创建时间戳(CPUDT、CPUTM)作为事件时间。 - 选择“已暂存”事件:读取存储暂存单据抬头的VBKPF表。该表中的创建时间戳代表暂存事件发生时间。
- 选择“工作流”事件(已提交、已批准、已拒绝):查询SWW_WI2OBJ等工作流表,将日记账分录对象关联到工作流实例;并查询SWWLOGHIST或SWWIHEAD,获取具体步骤的详情和时间。您需要确认系统中用于提交、批准和拒绝的具体工作流任务ID。
- 选择“变更”和“更正”事件:查询变更单据表CDHDR(抬头)和CDPOS(项目),筛选条件为
OBJECTCLAS = 'BELEG'。对于“过账后变更”,筛选变更时间晚于单据过账日期的记录。对于“已更正”,筛选暂存或已拒绝单据的变更记录。 - 选择“冲销”和“已清账”事件:在BKPF中查找
STBLG字段(被冲销单据编号)有值的单据,以识别冲销。冲销单据的创建时间即为冲销事件时间。对于清账事件,从ACDOCA中选取指定日记账分录行项目的最新清账日期(AUGDT)。 - 合并并排序数据:提取各项活动的数据时,将结果追加到最终主内表。完成所有提取后,按
JournalEntryId和EventTime对主表排序,确保每个案例内的事件按时间先后排列。 - 生成输出文件:使用
OPEN DATASET、LOOP AT... TRANSFER和CLOSE DATASET语句,将排序后的最终内表写入SAP应用服务器上指定的文件路径。文件应为带表头行的CSV格式。 - 安排执行计划:如需定期提取,可使用事务代码
SM36创建后台作业,按指定计划(例如每周或每月)运行Z_PM_JE_EXTRACT程序,从而自动导出数据。
配置
- 日期范围:选择屏幕应要求填写日记账分录创建日期(
CPUDT)范围。建议每次提取3至6个月的数据,便于控制数据量并保证性能。 - 公司代码(
BUKRS):这是限制提取范围、确保数据与流程挖掘分析相关的重要筛选条件。不建议一次提取所有公司代码的数据。 - 单据类型(
BLART):可添加此可选筛选条件,以聚焦特定类型的日记账分录,例如总账科目过账“SA”或供应商发票“KR”。这有助于减少数据量并提高数据集的相关性。 - 文件路径:程序需要SAP应用服务器上的逻辑文件路径,用于写入输出文件。请确认路径有效,且SAP系统用户拥有该目录的写入权限。可使用事务代码
AL11管理和查看服务器目录。 - 工作流任务ID:提取工作流事件(已提交、已批准、已拒绝)的逻辑必须配置为组织日记账分录审批工作流所使用的具体任务ID。这些ID通常为自定义配置,应由工作流顾问或开发人员确认。
- 前提条件:运行程序的用户或系统账户需要拥有创建和运行ABAP程序的开发权限(
S_DEVELOP),并能广泛读取财务表(BKPF、ACDOCA)、变更日志表(CDHDR、CDPOS)和工作流表(SWW*)。
查询示例 abap
REPORT Z_PM_JE_EXTRACT.
*&---------------------------------------------------------------------*
*&-- Data Structures for Event Log --*
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
journalentryid TYPE string,
activityname TYPE string,
eventtime TYPE string,
createdbyuser TYPE uname,
companycode TYPE bukrs,
journalentrytype TYPE blart,
postingdate TYPE budat,
amountinlocalcurrency TYPE wrbtr,
END OF ty_event_log.
*&---------------------------------------------------------------------*
*&-- Selection Screen Definition --*
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
PARAMETERS: p_erdat_fr TYPE dats OBLIGATORY DEFAULT sy-datum-30,
p_erdat_to TYPE dats OBLIGATORY DEFAULT sy-datum.
SELECT-OPTIONS: so_bukrs FOR bkpf-bukrs OBLIGATORY.
PARAMETERS: p_fpath TYPE string OBLIGATORY DEFAULT '/usr/sap/trans/tmp/je_event_log.csv'.
SELECTION-SCREEN END OF BLOCK b1.
*&---------------------------------------------------------------------*
*&-- Internal Tables --*
*&---------------------------------------------------------------------*
DATA: gt_event_log TYPE TABLE OF ty_event_log.
*&---------------------------------------------------------------------*
*&-- Main Processing Block --*
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM get_created_posted_events.
PERFORM get_parked_events.
PERFORM get_attachment_events.
PERFORM get_workflow_events.
PERFORM get_change_events.
PERFORM get_cleared_events.
PERFORM get_reversal_events.
SORT gt_event_log BY journalentryid eventtime.
PERFORM write_output_file.
*&---------------------------------------------------------------------*
*&-- Subroutines for Extracting Individual Activities --*
*&---------------------------------------------------------------------*
FORM get_created_posted_events.
DATA: lt_bkpf TYPE TABLE OF bkpf,
ls_event_log TYPE ty_event_log,
lv_timestamp TYPE string.
SELECT * FROM bkpf INTO TABLE lt_bkpf
WHERE bukrs IN so_bukrs
AND cpudt BETWEEN p_erdat_fr AND p_erdat_to.
LOOP AT lt_bkpf ASSIGNING FIELD-SYMBOL(<fs_bkpf>).
CLEAR ls_event_log.
CONCATENATE <fs_bkpf>-bukrs <fs_bkpf>-belnr <fs_bkpf>-gjahr INTO ls_event_log-journalentryid.
ls_event_log-companycode = <fs_bkpf>-bukrs.
ls_event_log-journalentrytype = <fs_bkpf>-blart.
ls_event_log-postingdate = <fs_bkpf>-budat.
ls_event_log-createdbyuser = <fs_bkpf>-usnam.
" Timestamp format YYYY-MM-DDTHH:MI:SS
CONCATENATE <fs_bkpf>-cpudt(4) '-' <fs_bkpf>-cpudt+4(2) '-' <fs_bkpf>-cpudt+6(2) 'T' <fs_bkpf>-cputm(2) ':' <fs_bkpf>-cputm+2(2) ':' <fs_bkpf>-cputm+4(2) INTO lv_timestamp.
ls_event_log-eventtime = lv_timestamp.
" Activity: Journal Entry Created
ls_event_log-activityname = 'Journal Entry Created'.
SELECT SUM( hsl ) INTO ls_event_log-amountinlocalcurrency FROM acdoca WHERE belnr = <fs_bkpf>-belnr AND gjahr = <fs_bkpf>-gjahr AND bukrs = <fs_bkpf>-bukrs.
APPEND ls_event_log TO gt_event_log.
" Activity: Journal Entry Posted (if not parked)
IF <fs_bkpf>-bstat = ' '.
ls_event_log-activityname = 'Journal Entry Posted'.
APPEND ls_event_log TO gt_event_log.
" Activity: Manual Posting Identified (based on T-Code)
CASE <fs_bkpf>-tcode.
WHEN 'FB01' OR 'F-02' OR 'FB50' OR 'F-22' OR 'F-43'.
ls_event_log-activityname = 'Manual Posting Identified'.
APPEND ls_event_log TO gt_event_log.
ENDCASE.
ENDIF.
ENDLOOP.
ENDFORM.
FORM get_parked_events.
DATA: ls_event_log TYPE ty_event_log, lv_timestamp TYPE string.
SELECT * FROM vbkpf
WHERE bukrs IN so_bukrs
AND cpudt BETWEEN p_erdat_fr AND p_erdat_to.
CLEAR ls_event_log.
CONCATENATE vbkpf-bukrs vbkpf-belnr vbkpf-gjahr INTO ls_event_log-journalentryid.
CONCATENATE vbkpf-cpudt(4) '-' vbkpf-cpudt+4(2) '-' vbkpf-cpudt+6(2) 'T' vbkpf-cputm(2) ':' vbkpf-cputm+2(2) ':' vbkpf-cputm+4(2) INTO lv_timestamp.
ls_event_log-activityname = 'Journal Entry Parked'.
ls_event_log-eventtime = lv_timestamp.
ls_event_log-createdbyuser = vbkpf-usnam.
ls_event_log-companycode = vbkpf-bukrs.
ls_event_log-journalentrytype = vbkpf-blart.
ls_event_log-postingdate = vbkpf-budat.
APPEND ls_event_log TO gt_event_log.
ENDSELECT.
ENDFORM.
FORM get_attachment_events.
DATA: lt_bdocs TYPE TABLE OF srgbtbrel, ls_event_log TYPE ty_event_log, lv_timestamp TYPE string.
SELECT * FROM srgbtbrel INTO TABLE lt_bdocs
WHERE typeid_a = 'BUS2081' " Object type for Accounting Document
AND catid_a = 'BO'.
LOOP AT lt_bdocs ASSIGNING FIELD-SYMBOL(<fs_bdocs>).
CHECK <fs_bdocs>-instid_a(4) IN so_bukrs.
DATA(lv_bukrs) = <fs_bdocs>-instid_a(4).
DATA(lv_belnr) = <fs_bdocs>-instid_a+4(10).
DATA(lv_gjahr) = <fs_bdocs>-instid_a+14(4).
SELECT SINGLE cpudt, cputm, usnam, blart, budat FROM bkpf
INTO (DATA(lv_cpudt), DATA(lv_cputm), DATA(lv_usnam), DATA(lv_blart), DATA(lv_budat))
WHERE bukrs = lv_bukrs AND belnr = lv_belnr AND gjahr = lv_gjahr.
IF sy-subrc = 0 AND lv_cpudt BETWEEN p_erdat_fr AND p_erdat_to.
CLEAR ls_event_log.
CONCATENATE lv_bukrs lv_belnr lv_gjahr INTO ls_event_log-journalentryid.
" Note: Using document creation time as a proxy for attachment time.
CONCATENATE lv_cpudt(4) '-' lv_cpudt+4(2) '-' lv_cpudt+6(2) 'T' lv_cputm(2) ':' lv_cputm+2(2) ':' lv_cputm+4(2) INTO lv_timestamp.
ls_event_log-activityname = 'Supporting Documentation Attached'.
ls_event_log-eventtime = lv_timestamp.
ls_event_log-createdbyuser = lv_usnam.
ls_event_log-companycode = lv_bukrs.
ls_event_log-journalentrytype = lv_blart.
ls_event_log-postingdate = lv_budat.
APPEND ls_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
FORM get_workflow_events.
" This is a simplified example. Real workflow logic can be complex.
" You must identify your specific Task IDs for these events.
DATA: ls_event_log TYPE ty_event_log, lv_timestamp TYPE string.
DATA: BEGIN OF ls_wi, wi_id TYPE sww_wiid, cr_date TYPE sww_cd, cr_time TYPE sww_ct, task TYPE sww_task, instid TYPE swo_typeid, END OF ls_wi.
SELECT h~wi_id h~cr_date h~cr_time h~wi_rh_task o~instid
FROM swwwihead AS h
JOIN sww_wi2obj AS o ON h~wi_id = o~wi_id
INTO @ls_wi
WHERE o~typeid = 'BUS2081' AND o~catid = 'BO'
AND h~cr_date BETWEEN @p_erdat_fr AND @p_erdat_to.
DATA(lv_bukrs) = ls_wi-instid(4).
DATA(lv_belnr) = ls_wi-instid+4(10).
DATA(lv_gjahr) = ls_wi-instid+14(4).
IF lv_bukrs IN so_bukrs.
CLEAR ls_event_log.
CONCATENATE lv_bukrs lv_belnr lv_gjahr INTO ls_event_log-journalentryid.
CONCATENATE ls_wi-cr_date(4) '-' ls_wi-cr_date+4(2) '-' ls_wi-cr_date+6(2) 'T' ls_wi-cr_time(2) ':' ls_wi-cr_time+2(2) ':' ls_wi-cr_time+4(2) INTO lv_timestamp.
ls_event_log-eventtime = lv_timestamp.
ls_event_log-companycode = lv_bukrs.
CASE ls_wi-task.
WHEN '[Your Submit Task ID]'. " e.g., TS20000139
ls_event_log-activityname = 'Journal Submitted For Review'.
APPEND ls_event_log TO gt_event_log.
WHEN '[Your Approve Task ID]'. " e.g., TS20000142
ls_event_log-activityname = 'Journal Entry Approved'.
APPEND ls_event_log TO gt_event_log.
WHEN '[Your Reject Task ID]'. " e.g., TS20000141
ls_event_log-activityname = 'Journal Entry Rejected'.
APPEND ls_event_log TO gt_event_log.
ENDCASE.
ENDIF.
ENDSELECT.
ENDFORM.
FORM get_change_events.
DATA: lt_cdhdr TYPE TABLE OF cdhdr, ls_event_log TYPE ty_event_log, lv_timestamp TYPE string.
SELECT * FROM cdhdr INTO TABLE lt_cdhdr
WHERE objectclas = 'BELEG'
AND udate BETWEEN p_erdat_fr AND p_erdat_to.
LOOP AT lt_cdhdr ASSIGNING FIELD-SYMBOL(<fs_cdhdr>).
DATA(lv_bukrs) = <fs_cdhdr>-objectid(4).
DATA(lv_belnr) = <fs_cdhdr>-objectid+4(10).
DATA(lv_gjahr) = <fs_cdhdr>-objectid+14(4).
IF lv_bukrs IN so_bukrs.
SELECT SINGLE bstat, budat, blart FROM bkpf
INTO (DATA(lv_bstat), DATA(lv_budat), DATA(lv_blart))
WHERE bukrs = lv_bukrs AND belnr = lv_belnr AND gjahr = lv_gjahr.
IF sy-subrc = 0.
CLEAR ls_event_log.
CONCATENATE lv_bukrs lv_belnr lv_gjahr INTO ls_event_log-journalentryid.
CONCATENATE <fs_cdhdr>-udate(4) '-' <fs_cdhdr>-udate+4(2) '-' <fs_cdhdr>-udate+6(2) 'T' <fs_cdhdr>-utime(2) ':' <fs_cdhdr>-utime+2(2) ':' <fs_cdhdr>-utime+4(2) INTO lv_timestamp.
ls_event_log-eventtime = lv_timestamp.
ls_event_log-createdbyuser = <fs_cdhdr>-username.
ls_event_log-companycode = lv_bukrs.
ls_event_log-journalentrytype = lv_blart.
ls_event_log-postingdate = lv_budat.
IF lv_bstat = ' ' AND <fs_cdhdr>-udate > lv_budat.
ls_event_log-activityname = 'Journal Entry Changed After Posting'.
APPEND ls_event_log TO gt_event_log.
ELSEIF lv_bstat <> ' '.
ls_event_log-activityname = 'Journal Entry Corrected'.
APPEND ls_event_log TO gt_event_log.
ENDIF.
ENDIF.
ENDIF.
ENDLOOP.
ENDFORM.
FORM get_cleared_events.
DATA: ls_event_log TYPE ty_event_log, lv_timestamp TYPE string.
DATA: BEGIN OF ls_clear, belnr TYPE belnr_d, gjahr TYPE gjahr, bukrs TYPE bukrs, augdt TYPE augdt, END OF ls_clear, lt_clear LIKE TABLE OF ls_clear.
SELECT belnr, gjahr, bukrs, MAX( augdt ) AS augdt FROM acdoca
INTO TABLE @lt_clear
WHERE bukrs IN @so_bukrs
AND augdt NE '00000000'
AND augdt BETWEEN @p_erdat_fr AND @p_erdat_to
GROUP BY belnr, gjahr, bukrs.
LOOP AT lt_clear INTO ls_clear.
SELECT SINGLE usnam, blart, budat FROM bkpf
INTO (DATA(lv_usnam), DATA(lv_blart), DATA(lv_budat))
WHERE bukrs = ls_clear-bukrs AND belnr = ls_clear-belnr AND gjahr = ls_clear-gjahr.
IF sy-subrc = 0.
CLEAR ls_event_log.
CONCATENATE ls_clear-bukrs ls_clear-belnr ls_clear-gjahr INTO ls_event_log-journalentryid.
CONCATENATE ls_clear-augdt(4) '-' ls_clear-augdt+4(2) '-' ls_clear-augdt+6(2) 'T12:00:00' INTO lv_timestamp. " Clearing date has no time, use midday
ls_event_log-activityname = 'Journal Entry Cleared'.
ls_event_log-eventtime = lv_timestamp.
ls_event_log-createdbyuser = lv_usnam.
ls_event_log-companycode = ls_clear-bukrs.
ls_event_log-journalentrytype = lv_blart.
ls_event_log-postingdate = lv_budat.
APPEND ls_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
FORM get_reversal_events.
DATA: lt_reversals TYPE TABLE OF bkpf, ls_event_log TYPE ty_event_log, lv_timestamp TYPE string.
SELECT * FROM bkpf INTO TABLE lt_reversals
WHERE bukrs IN so_bukrs
AND cpudt BETWEEN p_erdat_fr AND p_erdat_to
AND stblg IS NOT NULL.
LOOP AT lt_reversals ASSIGNING FIELD-SYMBOL(<fs_rev>).
SELECT SINGLE usnam, blart, budat FROM bkpf
INTO (DATA(lv_usnam), DATA(lv_blart), DATA(lv_budat))
WHERE bukrs = <fs_rev>-bukrs AND belnr = <fs_rev>-stblg AND gjahr = <fs_rev>-gjahr.
IF sy-subrc = 0.
CLEAR ls_event_log.
CONCATENATE <fs_rev>-bukrs <fs_rev>-stblg <fs_rev>-gjahr INTO ls_event_log-journalentryid.
CONCATENATE <fs_rev>-cpudt(4) '-' <fs_rev>-cpudt+4(2) '-' <fs_rev>-cpudt+6(2) 'T' <fs_rev>-cputm(2) ':' <fs_rev>-cputm+2(2) ':' <fs_rev>-cputm+4(2) INTO lv_timestamp.
ls_event_log-activityname = 'Journal Entry Reversal Processed'.
ls_event_log-eventtime = lv_timestamp.
ls_event_log-createdbyuser = lv_usnam.
ls_event_log-companycode = <fs_rev>-bukrs.
ls_event_log-journalentrytype = lv_blart.
ls_event_log-postingdate = lv_budat.
APPEND ls_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
FORM write_output_file.
DATA: lv_line TYPE string.
FIELD-SYMBOLS: <fs_event_log> TYPE ty_event_log.
OPEN DATASET p_fpath FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
IF sy-subrc NE 0.
MESSAGE 'Error opening file.' TYPE 'E'.
RETURN.
ENDIF.
" Write Header
lv_line = 'JournalEntryId,ActivityName,EventTime,CreatedByUser,CompanyCode,JournalEntryType,PostingDate,AmountInLocalCurrency'.
TRANSFER lv_line TO p_fpath.
LOOP AT gt_event_log ASSIGNING <fs_event_log>.
CONCATENATE <fs_event_log>-journalentryid <fs_event_log>-activityname <fs_event_log>-eventtime <fs_event_log>-createdbyuser <fs_event_log>-companycode <fs_event_log>-journalentrytype <fs_event_log>-postingdate <fs_event_log>-amountinlocalcurrency
INTO lv_line SEPARATED BY ','.
TRANSFER lv_line TO p_fpath.
ENDLOOP.
CLOSE DATASET p_fpath.
WRITE: / 'File successfully written to', p_fpath.
ENDFORM. 优化订单到报告日记账分录流程,提升效率
改进流程,将订单到报告日记账分录的周期时间缩短30%。
无需信用卡,几分钟即可完成设置。