您的记录到报告流程:日记账分录数据模板
您的记录到报告流程:日记账分录数据模板
- 建议收集的属性
- 需要跟踪的关键活动
- 实用提取指南
记录到报告-日记账分录属性
| 名称 | 说明 | ||
|---|---|---|---|
| 事件时间 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 | 日记账分录流程中特定时点发生的业务活动名称。 | ||
| 说明 Activity代表日记账分录生命周期中的特定步骤或事件,例如“日记账分录已创建”“日记账已提交审核”或“日记账分录已过账”。这些活动通常根据系统中记录的变更日志、状态更新或交易代码派生。 分析活动有助于可视化流程顺序、识别常见路径并发现偏离标准过程的情况。它是计算活动频次、步骤间等待时间和一致性率等指标的基础。 为什么重要 它定义流程中的各个步骤,使您能够构建流程图并分析工作流模式。 获取位置 数据来源包括抬头表和项目表中的状态字段(例如BKPF-BSTAT)、变更凭证日志(CDHDR/CDPOS)以及工作流日志。 示例 日记账分录已创建日记账分录已暂存日记账分录已提交审核日记账分录已批准日记账分录已过账 | |||
| 公司代码 CompanyCode | 记账日记账分录所属公司或法人实体的唯一标识。 | ||
| 说明 公司代码是SAP Financials中的基础组织单位,代表能够独立生成财务报表的法人实体。每条日记账分录都会分配到特定公司代码。 该属性对于细分和比较组织不同部分的流程绩效至关重要。分析人员可以使用它筛选特定法人实体的流程视图,比较不同公司代码之间的拒绝率,或识别特定区域的流程差异。 为什么重要 支持在组织内部不同法人实体或业务单元之间筛选和比较日记账分录流程。 获取位置 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 | 以公司代码本位币表示的日记账分录总金额。 | ||
| 说明 此属性表示日记账分录的财务规模。通常,它是凭证中所有借方或贷方行项目绝对值之和,并已换算为公司代码的本位币。 按金额分析可以根据财务影响细分流程。例如,高金额分录可能比低金额分录遵循更严格的审批流程。该属性有助于优先改进财务风险最高的交易。 为什么重要 提供分录的财务金额,支持分析流程行为如何随涉及金额变化而变化。 获取位置 针对指定日记账分录(BELNR),汇总行项目表BSEG中的金额(字段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 | |||
| 审批周期时间 ApprovalCycleTime | 从日记账分录提交审批,到审批通过或被拒绝所经过的时间。 | ||
| 说明 该计算指标专门衡量审批阶段的持续时间,即从“日记账已提交审核”活动到后续“日记账分录已批准”或“日记账分录已拒绝”活动之间的时间。 该KPI对于识别审批工作流中的瓶颈至关重要。审批周期过长可能显著延误整体流程。按审批人、公司代码或日记账分录类型分析该指标,可以发现具体的改进方向。 为什么重要 单独衡量审批步骤的持续时间,帮助定位并解决审核和审批工作流中的瓶颈。 获取位置 计算“日记账已提交审核”事件与“日记账分录已批准”或“日记账分录已拒绝”事件之间的时间差。 示例 1天2小时4小时25分钟5天0小时 | |||
| 审批用户 ApproverUser | 审批或拒绝日记账分录人员的用户ID。 | ||
| 说明 此属性用于标识负责审核提交的日记账分录并作出决定的用户。在多级审批工作流中,一条日记账分录可能对应多名审批人。 该信息对于详细分析审批流程十分重要。您可以据此衡量不同审批人的工作负载,计算个人审批时长,并识别审批链中的瓶颈。它直接支持“用户活动与吞吐量”仪表板。 为什么重要 识别负责审批的人员,支持分析审批工作负载、绩效和瓶颈。 获取位置 来源于工作流日志,例如SWW_WI2OBJ、SWWLOG,或变更文档表CDHDR/CDPOS,依据执行审批步骤的人员进行追踪。 示例 DMILLERFWHITEKCHEN | |||
| 文档状态 DocumentStatus | 日记账分录当前的处理状态,例如已暂存、已记账或已清账。 | ||
| 说明 文档状态表示日记账分录在整个生命周期中的所处状态。例如,“已暂存”文档已保存,但尚未记入总账;“已记账”文档则表示处理已完成。 分析状态有助于了解工作流转并识别瓶颈。大量文档长时间处于“已暂存”或“待审批”状态,可能表明流程存在低效环节。该属性也是派生流程活动的重要来源。 为什么重要 展示日记账分录在生命周期中的当前位置,帮助识别队列和瓶颈。 获取位置 SAP S/4HANA表BKPF,字段BSTAT(文档状态)。 示例 VAB | |||
| 是否手动记账 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 | 表示活动完成时间的时间戳。 | ||
| 说明 End Time表示活动完成的时间。在许多事件日志中,活动的Start Time和End Time相同,代表瞬时事件。但对于具有可测量持续时间的活动,例如用户主动审核文档,该属性可以记录实际持续时间。 单独记录End Time后,您可以更准确地计算活动处理时间和等待时间,并区分任务实际处理所用的时间与其在队列中空闲等待的时间。 为什么重要 支持精确计算活动处理时间,并将主动处理时间与空闲等待时间区分开来。 获取位置 对于原子事件,通常与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中创建,但尚未过账至总账。这是日记账分录生命周期的起点。 | ||
| 为什么重要 这是流程的主要开始事件。分析从此事件到过账所需的时间,对于衡量整体周期时间和识别初始数据录入延误至关重要。 获取位置 对于指定凭证编号(BELNR),可使用SAP表BKPF中的创建日期(CPUDT)和创建时间(CPUTM)字段明确捕获此事件。 采集 使用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)字段计算此结果。系统使用已知人工T-Code列表(例如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 View I_JournalEntry、I_JournalEntryItem以及表CDHDR、CDPOS、SRGBREL、SOOD、SWW_WI2OBJ和SWWLOGHIST拥有读取权限。通常可通过SAP HANA Studio、DBeaver等数据库客户端,或使用Eclipse的SAP ABAP Development Tools(ADT)访问。
- 识别系统特定配置:运行查询前,您必须确定Journal Entry审批工作流使用的具体任务代码。请咨询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等列均已按预期填充。结果集应为Journal Entry生命周期中的每个不同业务事件返回一行记录。
- 将数据导出为CSV:使用SQL工具将完整结果集导出为单个CSV文件。确保文件采用UTF-8编码,以避免特殊字符显示异常。
- 准备上传:上传到流程挖掘工具前,确认CSV文件包含所需表头。数据已按事件日志结构整理,通常无需进一步转换或透视。
配置
- Core Data Services(CDS)View:提取主要使用
I_JournalEntry获取抬头数据,使用I_JournalEntryItem获取行项目和金额明细。这些View为Universal Journal(ACDOCA)提供了简化且语义丰富的访问接口。 - 支持表:为呈现完整流程,查询还会关联多个标准SAP表:
CDHDR和CDPOS用于跟踪单据变更。SRGBREL和SOOD用于识别通过Generic Object Services(GOS)关联附件的时间。SWW_WI2OBJ和SWWLOGHIST用于提取审批工作流中的关键事件。
- 日期范围筛选:必须按具体日期范围筛选数据,以控制性能。在
WHERE子句中使用I_JournalEntry.CreationDateTime字段。初次分析建议选择3至6个月的范围。 - 组织筛选:始终按
CompanyCode筛选,将提取范围限制在相关法人实体内。在大型系统中一次查询所有公司代码,可能导致执行时间过长。 - 工作流任务ID:查询包含工作流任务ID占位符,例如
[Workflow Approved Task ID]。这些ID在每个SAP安装环境中都不同,必须正确配置,才能提取工作流活动。缺少这些ID时,将无法捕获提交、审批或拒绝事件。 - 前提条件:执行用户需要对财务、系统和工作流表拥有广泛的读取授权。这些权限通常不是默认权限,必须单独分配。
a 示例查询 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提供会计凭证及行项目数据,但无法单独可靠地呈现所有暂存、提交、拒绝、更正、审批或附件事件。请将工作流和附件数据源占位符替换为您实施方案中经批准的视图或表。如果某个数据源不可用,请勿虚构事件。请配置相应数据源,或在获得书面批准后排除该活动。
- 设置所需日期范围、公司代码、凭证类型和客户端等提取参数。建议初次验证使用三至六个月的范围。根据约定的流程范围,对运营事件使用事件时间范围,对会计事件使用过账日期范围。
- 在经批准的HANA SQL客户端中运行完整SQL查询。该查询会为每个明确提取的活动创建一行事件。它使用BKPF和ACDOCA提取会计事件,并使用已配置的数据源视图提取工作流、附件、变更、清账和冲销事件。查询不会根据凭证是否存在来推断活动。
- 检查输出架构。JournalEntryId是案例标识,ActivityName是活动标签,EventTime是事件时间戳;在数据可用时,查询还会返回建议的业务属性。确认EventTime为时间戳,并确认所有行的JournalEntryId和ActivityName均不为空。
- 通过将不同JournalEntryId的值与所选客户端、公司代码、会计年度和日期范围对应的预期BKPF数据量进行比较,核对会计数据范围。请单独核对工作流和附件数据范围,因为其保留规则和时间戳规则可能与会计数据不同。
- 验证事件顺序和重复行为。除非流程设计明确要求按行项目记录事件,否则ACDOCA中的多个行项目不得生成重复的会计事件。使用查询中的聚合逻辑,按日记账分录和事件类型生成一条会计事件,同时在可用时保留已配置数据源的事件标识。
- 将结果导出为UTF-8编码的CSV或其他ProcessMind支持的表格格式。保留准确的列名JournalEntryId、ActivityName和EventTime。按JournalEntryId和EventTime对文件排序,并将其他属性保留为列。将文件上传至ProcessMind,并将JournalEntryId配置为案例标识,将ActivityName配置为活动,将EventTime配置为事件时间戳。
配置
- **日期范围:**从三至六个月开始。性能测试使用更短范围,只有在验证行数和事件覆盖率后再扩大范围。
- **客户端和公司范围:**设置[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,并在经批准的报表窗口执行。系统支持时,通过客户端、会计年度、公司代码和过账日期谓词实现分区裁剪。
- **重复处理:**在可用时使用来源事件标识。如果来源可能包含重复的技术记录,请应用已记录的去重规则,但不要合并实际独立的工作流操作。
- **前提条件:**所需数据库授权、经批准的SAP HANA连接、对已配置工作流和附件来源的访问权限、适当的SAP Financial Accounting及工作流配置,以及ProcessMind支持的导出格式。
a 示例查询 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,然后点击“创建”。填写合适的标题,将“类型”设置为“可执行程序”,并将其保存为本地对象或保存到程序包中。 - 定义选择屏幕:在程序中定义参数和选择选项,供用户筛选数据。应包括Journal Entry创建日期范围(
P_CPUDT_FR、P_CPUDT_TO)、Company Code选择选项(SO_BUKRS),以及应用服务器输出文件路径(P_FPATH)。 - 声明数据结构:定义与所需事件日志格式一致的内表结构,用于保存最终输出。同时,为需要读取的SAP表声明内表和工作区,例如BKPF、ACDOCA、CDHDR、CDPOS及各类工作流表。
- 实现数据选择逻辑:编写ABAP核心逻辑,提取12项所需活动的数据。为每项活动创建独立子例程(FORM),以保持代码结构清晰。例如,创建
get_created_events、get_parked_events和get_workflow_events等FORM。 - 选择“Created”和“Posted”事件:根据用户在选择屏幕中设置的条件读取BKPF表。BKPF中的记录表示创建事件。状态
BSTAT = ' '的凭证视为已过账。使用创建时间戳(CPUDT、CPUTM)作为事件时间。 - 选择“Parked”事件:读取存储暂存凭证抬头的VBKPF表。该表中的创建时间戳代表暂存事件。
- 选择“Workflow”事件(Submitted、Approved、Rejected):查询SWW_WI2OBJ等工作流表,将Journal Entry对象关联到工作流实例,并查询SWWLOGHIST或SWWIHEAD获取具体步骤的详情和时间。您需要确定系统中用于提交、审批和拒绝的具体工作流任务ID。
- 选择“Change”和“Correction”事件:查询变更凭证表CDHDR(抬头)和CDPOS(项目),筛选
OBJECTCLAS = 'BELEG'。对于“Changed After Posting”,筛选变更时间晚于凭证过账日期的记录。对于“Corrected”,筛选暂存或拒绝凭证的变更记录。 - 选择“Reversal”和“Cleared”事件:通过查找BKPF中
STBLG字段(冲销凭证编号)有值的凭证识别冲销事件。冲销事件时间为冲销凭证的创建时间。通过从ACDOCA中选择某个Journal Entry行项目的最新清账日期(AUGDT)识别清账事件。 - 合并并排序数据:每项活动完成数据选择后,将结果追加到最终主内表。所有选择完成后,按
JournalEntryId和EventTime对主表排序,确保每个案例内按时间顺序排列。 - 生成输出文件:使用
OPEN DATASET、LOOP AT... TRANSFER和CLOSE DATASET语句,将排序后的最终内表内容写入SAP应用服务器上的指定文件路径。文件应为带表头的CSV格式。 - 安排执行计划:如需定期提取,可使用事务代码
SM36创建后台作业,按预定计划运行Z_PM_JE_EXTRACT程序,例如每周或每月运行。这样即可自动完成数据导出。
配置
- 日期范围:选择屏幕应为Journal Entry创建日期(
CPUDT)设置必填日期范围。建议按易于管理的批次提取数据,例如每次提取3至6个月,以确保良好性能。 - 公司代码(
BUKRS):这是限制提取范围的关键筛选条件,应仅包含与流程挖掘分析相关的法人实体。不建议一次提取所有公司代码。 - 凭证类型(
BLART):您可以添加此可选筛选条件,聚焦特定类型的Journal Entry,例如总账过账“SA”或供应商发票“KR”。这有助于减少数据量并提高数据集相关性。 - 文件路径:程序需要SAP应用服务器上的逻辑文件路径,用于写入输出文件。请确保路径有效,且SAP系统用户拥有该目录的写入权限。使用事务
AL11管理和查看服务器目录。 - 工作流任务ID:提取工作流事件(Submitted、Approved、Rejected)的逻辑必须配置为使用您所在组织Journal Entry审批工作流中的具体任务ID。这些ID通常为自定义配置,需要由工作流顾问或开发人员确定。
- 前提条件:执行程序的用户或系统账户需要创建和运行ABAP程序的开发者授权(
S_DEVELOP),以及对财务表(BKPF、ACDOCA)、变更日志表(CDHDR、CDPOS)和工作流表(SWW*)的广泛读取权限。
a 示例查询 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. 优化Record to Report Journal Entry,实现高效运营
改进您的流程,将Record to Report Journal Entry周期时间缩短30%。
无需信用卡,几分钟即可完成设置。