数据模板:应付账款发票处理
应付账款发票处理数据模板
- 全面分析的推荐属性
- 需有效追踪的关键流程活动
- 分步数据提取指南
应付账款发票处理属性
| 名称 | 描述 | ||
|---|---|---|---|
Event 时间 EventTime | 活动发生的精确日期和时间。 | ||
描述 Event Time 是与每项活动关联的时间戳,它提供了发票事件的先后顺序。这些数据对于理解流程流转和进行任何基于时间的分析都至关重要。 在分析中,Event Time 用于正确排序活动、计算不同步骤间的周期时间、识别等待时间,并分析不同时间段(例如,月度环比)的流程绩效。它是所有与时长相关的 KPI 的基础。 为何重要 此时间戳对于事件按时间顺序排序以及计算所有基于时间的指标(如周期时间、持续时间等)至关重要,这些都是流程挖掘的基础。 获取方式 源自 SAP 表中的多个日期/时间字段,例如创建日期(BKPF-CPUDT)、过账日期(BKPF-BUDAT)、清账日期(BSAK-AUGDT)或变更日志时间戳(CDHDR-UDATE/UTIME)。 示例 2023-10-01T09:00:00Z2023-10-05T14:30:15Z2023-10-15T11:21:05Z | |||
发票 Invoice | 发票 Document 的唯一标识符,作为应付账款流程的主要 case ID。 | ||
描述 发票(Invoice)是连接所有相关活动的核心 object,涵盖从接收到付款的全过程。在SAP S/4HANA中,它通常是一个由公司代码(BUKRS)、唯一 Document Number(BELNR)和会计年度(GJAHR)组成的复合键。 按 Invoice 进行分析可提供 Invoice 生命周期 的完整端到端视图。这对于计算总周期时间等关键 metrics、识别单个 Invoice 的 bottlenecks 以及理解 Invoice 在流程中可能经历的不同路径至关重要。 为何重要 它能唯一标识每张发票的流转轨迹,从而可以追踪其完整的生命周期,并逐案分析流程绩效。 获取方式 这是一个复合键,它使用字段 BUKRS、BELNR 和 GJAHR 从表 BKPF (会计凭证 header) 或 RBKP (凭证 header:发票收据) 中派生而来。 示例 1000-1900000001-20231710-1900000002-20232000-5100000003-2024 | |||
活动 ActivityName | 在发票处理生命周期中发生的特定业务 event 或步骤的名称。 | ||
描述 活动(Activity)代表着应付账款流程中一个独特的阶段或动作,例如“收到发票”、“发票已过账”或“付款已执行”。它们是流程图的基本构成要素。 分析活动是流程挖掘的核心。它有助于可视化流程流、识别常见路径、检测与标准流程的偏差,并衡量每个步骤的频率和持续时间。针对特定发票的这些活动序列,构成了其完整的流程旅程。 为何重要 它定义了流程的各个步骤,有助于实现流程的可视化与分析、识别瓶颈,并发现返工循环。 获取方式 此信息源自多种来源,包括文档状态更改(例如BKPF-BSTAT)、更改凭证(CDHDR/CDPOS表)或Workflow日志。这通常需要定制的提取逻辑。 示例 发票收到发票已批准已执行付款发票已冻结付款 | |||
最后数据更新 LastDataUpdate | 指示此 record 数据上次从源系统刷新的 timestamp。 | ||
描述 此属性提供从 SAP S/4HANA 最新提取或更新 data (数据) 的日期和时间。这是一个 metadata (元数据) 字段,对于理解正在分析的 data (数据) 的“新鲜度”至关重要。 此信息对用户了解流程分析的实时性非常重要。它有助于管理对 data (数据) 延迟的预期,并且对于安排 data (数据) 刷新和维护 data (数据) 完整性至关重要。 为何重要 指示数据的时效性,确保用户了解其流程分析的更新程度。 获取方式 此值在从源系统抽取数据时,生成并标记在每条记录上。 示例 2024-05-20T04:00:00Z2024-05-21T04:00:00Z | |||
源系统 SourceSystem | 数据提取来源系统。 | ||
描述 此属性标识流程 data (数据) 的来源。在此视图中,该值通常为 'SAP S/4HANA'。 在拥有多个 ERP 或集成系统的环境中,此字段对于 data lineage (数据血缘) 和数据隔离至关重要。它确保分析在正确的 dataset (数据集) 上执行,并有助于通过追溯到来源来诊断 data (数据) 质量问题。 为何重要 识别数据的来源,这对于数据治理、故障排除以及在多系统环境中都至关重要。 获取方式 这通常是在数据抽取过程中添加的静态值,用于标记数据集的来源。 示例 SAP S/4HANASAP ECC 6.0S4H_PROD_100 | |||
供应商名称 VendorName | 提交发票的供应商名称。 | ||
描述 此属性包含供应商的官方名称。它通过发票凭证上存储的 Vendor Number (供应商编号) 进行关联。 供应商分析对于管理供应商关系和识别特定供应商相关的流程问题至关重要。它可以帮助回答诸如“哪些供应商提交的发票差异最多?”或“我们是否持续准时支付某些战略供应商?”等问题。此外,它与发票号码和金额一起,也是检测潜在重复付款的关键字段。 为何重要 允许按供应商分析流程绩效,有助于识别问题供应商并有效管理战略供应商关系。 获取方式 从供应商主数据表 LFA1(字段 NAME1)中检索,通过 BKPF 或 RBKP 中找到的供应商编号(LIFNR)进行关联。 示例 办公用品有限公司全球咨询集团Machine Parts GmbH | |||
公司代码 CompanyCode | 处理该发票的组织单位。 | ||
描述 公司代码 (Company Code) 是最小的组织单位,可以为其编制一套完整、独立的账务,用于对外报告。在应付账款场景中,它代表着向供应商付款的法人实体。 通过按公司代码进行分析,可以比较组织内不同法人实体的流程绩效。这有助于识别业务中哪些部门遵循标准流程,哪些部门效率更高、周期更长或返工率更高。 为何重要 此功能使得跨不同法人实体的流程绩效比较成为可能,有助于识别特定区域或业务单元的问题和最佳实践。 获取方式 主要在凭证抬头表(FI 发票的 BKPF-BUKRS 和 MM 发票的 RBKP-BUKRS)中查找。 示例 10001710US01DE01 | |||
发票到期日 InvoiceDueDate | 发票应支付给供应商的截止日期。 | ||
描述 发票到期日(Invoice Due Date)是向供应商付款的截止日期,旨在避免逾期付款滞纳金并维护良好的供应商关系。此日期根据发票的基准日期以及与供应商约定的付款条款计算。 该日期对于“付款合规与账龄”dashboard和“按时付款率”KPI至关重要。通过将到期日与实际付款日期进行比较,分析可以揭示付款是按时、提前还是逾期,这会产生直接的财务和关系影响。 为何重要 这是准时付款分析的主要驱动因素,有助于衡量付款绩效及其对供应商关系和滞纳金的影响。 获取方式 此日期通常是计算得出的。净到期日位于字段 BSEG-NETDT 中。它也可以从付款基准日期 (BSEG-ZFBDT) 和付款条件 (BSEG-ZTERM) 中推导出来。 示例 2023-10-312023-11-152024-01-10 | |||
发票金额 InvoiceAmount | 发票在原始单据货币下的总毛额。 | ||
描述 这是供应商提交的发票总金额,包括商品或服务的成本、税费以及任何其他费用,不含任何扣减或折扣。 发票金额是一个关键的财务属性,可用于广泛的分析。它有助于优先处理高价值发票,理解流程延迟的财务影响(例如,大额发票产生的滞纳金),以及对流程进行细分(例如,“高价值发票是否遵循不同的审批路径?”)。此外,它对于识别潜在的重复付款也至关重要。 为何重要 为流程提供财务背景,支持基于价值的分析,高价值发票的优先处理,以及财务影响的量化评估。 获取方式 在 RBKP-RMWWR(MM 发票的发票总金额)等表中查找,或从 BSEG(FI 发票的字段 WRBTR)中的行项目计算得出。 示例 1500.00250.7512345.50 | |||
用户名 UserName | 执行此活动的用户ID。 | ||
描述 此属性记录负责执行特定活动(例如过账、审批或结清发票)的 SAP user ID (用户ID)。它将流程步骤与单个用户关联起来。 通过用户名称进行分析对于理解工作量分配、识别优秀执行者以及确定可能需要额外培训的用户至关重要。它也是分析 dashboard (仪表板) 中审批瓶颈的关键,因为它有助于识别哪些特定审批人导致了流程延迟。 为何重要 此功能将活动关联到具体个人,从而可分析用户绩效、工作量,并确保职责分离政策的合规性。 获取方式 通常在抬头表(如 BKPF-USNAM(录入者))或变更凭证表(如 CDHDR-USERNAME(变更者))中找到。 示例 ABROWNJSMITHAP_AUTOMATION | |||
采购订单号 PurchaseOrderNumber | 发票关联的采购订单唯一标识符(如适用)。 | ||
描述 此属性将发票与预先批准的采购订单 (PO) 相关联。PO 编号的存在是 3-way match (三方匹配) 流程(PO-发票-收货)的基础。 这是进行合规性和效率分析的关键属性。它用于计算“无 PO 发票百分比”这一 KPI,该 KPI 衡量对采购政策的遵守情况。它也是“3-Way Matching Performance (三方匹配绩效)” dashboard (仪表板) 的基础,可用于分析有 PO 支持的发票的匹配流程。 为何重要 对于分析三向匹配效率、衡量采购政策合规性至关重要,它能识别未经采购订单(PO)处理的发票。 获取方式 在发票行项目表(如 MM 发票的 RSEG-EBELN 或 FI 发票的 BSEG-EBELN)中查找。 示例 45000012344500005678 | |||
付款条款 PaymentTerms | 与供应商协商一致的支付发票的条件,通常包括折扣机会。 | ||
描述 付款条款定义了付款到期日和潜在提前付款折扣的规则。例如,像“Z001”这样的条款可能对应“30天内付款,10天内付款可享2%折扣”。 此属性是“提前付款折扣获取率” dashboard 的基础。通过分析付款条款,可以识别所有有资格获得折扣的发票。将其与实际获得的折扣进行比较,可以揭示错失的节省机会,并衡量付款流程的效率。 为何重要 这对于分析提前付款折扣机会、衡量支付流程的财务绩效以及识别错失的节约机会至关重要。 获取方式 在供应商行项目表 BSEG-ZTERM 中查找,或在发票抬头 RBKP-ZTERM 中查找。 示例 Z0010001NT30 | |||
供应商发票号 VendorInvoiceNumber | 供应商在其单据上提供的发票编号。 | ||
描述 这是供应商自身会计系统中的参考编号,通常印在纸质或电子发票凭证上。在发票接收过程中,它通过人工输入或 OCR 技术捕获。 此字段对于运营目的和分析至关重要,特别是对于“潜在重复发票付款”仪表盘。检测重复项的常见方法是查找共享相同供应商名称、供应商发票号和发票金额的多个内部发票凭证。它是发票的主要外部参考。 为何重要 它是检测潜在重复支付的关键字段,也是与供应商沟通的主要外部参考依据。 获取方式 存储在单据抬头的“参考”字段中,通常是 BKPF-XBLNR。 示例 INV-2023-9876733401120231015-001 | |||
冻结原因 BlockingReason | 发票被冻结付款的原因,通常表明存在差异。 | ||
描述 当发票在三方匹配或其他验证步骤中未能通过验证检查时,它将被冻结付款。“冻结原因”说明了问题的性质,例如数量差异、价格差异或缺少收货凭证。 此属性对于“发票差异返工分析”仪表盘至关重要。分析不同冻结原因的频率有助于识别流程低效的根本原因。例如,如果“价格差异”是常见原因,则可能指向采购系统中的主数据问题。 为何重要 直接洞察发票差异和返工的根本原因,从而实现有针对性的流程改进工作。 获取方式 存储在 RSEG 等发票行项目表中,位于以 SPGR* 开头的字段(例如 SPGRP、SPGRQ、SPGRT)。也可在 RBKP_BLOCKED 中找到。 示例 价格差异数量差异缺少收货单 | |||
发票凭证类型 InvoiceDocumentType | 发票文件的分类,它控制着发票在SAP中的处理方式。 | ||
描述 单据类型(Document Type)是SAP中一个关键的配置元素,用于对会计凭证进行分类。例如,'KR'通常用于供应商发票,'RE'用于MM发票,'KG'用于供应商贷项凭证。此类型决定了编号范围和所需字段等。 在流程分析中,按单据类型筛选可以比较不同类型发票的流程流。例如,贷项凭证的审批流程可能与标准发票不同。这对于“发票审批路由变体”dashboard非常有用。 为何重要 允许根据不同发票类型的处理方式对流程进行细分,揭示处理路径和周期时间的变化。 获取方式 直接来自文档抬头表中的字段BKPF-BLART。 示例 KRREKG | |||
发票币种 InvoiceCurrency | 发票金额的货币代码(例如:USD, EUR)。 | ||
描述 此属性指定发票金额的计价币种。它为任何财务数值提供了必要的背景信息。 在跨国组织中,分析发票时不考虑其币种可能会产生误导。此字段允许正确处理财务 data (数据),可以通过将所有金额转换为单一报告币种,也可以通过按币种细分分析来了解区域财务活动。 为何重要 为发票金额提供必要的上下文信息,尤其在跨国环境中,有助于实现准确的财务分析和报告。 获取方式 主要在凭证抬头表 BKPF-WAERS 或 RBKP-WAERS 中查找。 示例 USDEURGBPJPY | |||
处理时间 ProcessingTime | 单个活动的持续时间。 | ||
描述 处理时间,即活动持续时间,是指一项活动的开始到结束之间所经过的时间。此指标从 event log data 中计算得出。 这一计算出的指标对于“活动持续时间与返工热力图” dashboard 至关重要。它有助于精准找出流程中哪些特定步骤耗时最多。分析处理时间可以揭示效率低下的环节,例如漫长的审批步骤或耗时的差异解决活动,从而指导有针对性的改进工作。 为何重要 量化单个活动所花费的时间,有助于识别流程中最耗时的步骤和瓶颈。 获取方式 通过计算同一张发票中,当前活动的“Event 时间”与后续活动的“Event 时间”之间的差值得出。 示例 P2DT3H4MPT5HP7D | |||
已享受折扣 DiscountTaken | 一个布尔标志,表示是否成功应用了提前付款折扣。 | ||
描述 此属性指示发票支付时是否实际取得了现金折扣。它是衡量应付账款 (AP) 流程财务效率的关键组成部分。 此标志是“提前付款折扣获取率”这一 KPI 的核心。通过筛选出可能获得折扣(基于付款条件)的发票,并分析此标志,企业可以精确计算节省了多少资金以及错失了多少节省机会。这为应付账款 (AP) 绩效提供了一个清晰、可量化的衡量标准。 为何重要 直接衡量成功获取可用早付折扣的程度,这对公司的利润底线有直接影响。 获取方式 通过检查付款凭证上的折扣金额字段(BSEG-SKNTO)是否大于零推导得出。 示例 真false | |||
是否自动化 IsAutomated | 一个标志,表示该活动是由系统自动执行而非人工操作。 | ||
描述 此布尔属性区分人工发起的活动和由系统 job (作业)、workflow (工作流) 或 bot (机器人) 执行的活动。例如,自动化的付款运行或系统生成的发票过账将被标记为自动化。 分析此属性有助于理解应付账款流程中的自动化水平。它可用于衡量自动化计划的成功,比较自动化与手动步骤的效率,并识别进一步的自动化机会。 为何重要 有助于衡量流程中的自动化程度,从而分析自动化效率并识别进一步改进的机会。 获取方式 此信息是根据“用户名称”(例如“SAP_SYSTEM”或“BATCHUSER”等系统用户ID),或与自动化作业相关的特定事务代码推导得出的。 示例 真false | |||
是否逾期付款 IsLatePayment | 一个布尔标志,表示发票是否在到期日后支付。 | ||
描述 此计算属性是一个简单的真/假标志,指示发票是否在其官方到期日之后支付。它是通过比较“结清日期”与“发票到期日”得出的。 此标志简化了“付款合规与账龄” dashboard (仪表板) 和“准时付款率” KPI 的分析。它允许轻松筛选和聚合,以统计逾期付款的数量,计算准时付款的百分比,并识别逾期付款率高的供应商或公司代码。 为何重要 直接衡量付款条款的合规性,简化按时付款KPI的计算,并有助于识别付款绩效不佳的环节。 获取方式 计算属性。逻辑为:如果“结清日期”大于“发票到期日”,则为真;否则为假。 示例 真false | |||
结清日期 ClearingDate | 完成付款并将发票从未清项中清除的日期。 | ||
描述 清账日期(Clearing Date)标志着发票的财务结算。它是“付款已清账”活动发生的日期,对于大多数成功的发票流程而言,这标志着最终步骤。 该日期用于计算实际付款日期,并与发票到期日进行比较。因此,它对于计算“按时付款率”KPI以及任何与付款绩效相关的分析至关重要。它也标志着计算端到端发票周期时间的终点。 为何重要 标志着发票的最终结算,是计算周期时间的终点,也是按时付款分析的基础。 获取方式 在已清算项目的表中查找,例如供应商的 BSAK-AUGDT。 示例 2023-10-282023-11-142024-01-09 | |||
应付账款发票处理活动
| 活动 | 描述 | ||
|---|---|---|---|
付款已清算 | 此活动标志着发票的最终结清,即付款和发票在子分类账中相互核销。这标志着整个流程已完成。 | ||
为何重要 作为流程的终点,此活动对于准确计算端到端周期时间至关重要,并确认负债已结清。 获取方式 这是一个明确的 event (事件),其特征是发票凭证 (表 BSEG) 的供应商行项目上的“结清日期” (AUGDT) 字段被填充。 捕获 使用发票行项目中的清账日期 (BSEG-AUGDT)。 事件类型 explicit | |||
发票已冻结付款 | 系统已自动或手动对发票设置了冻结,阻止其付款。这通常是由于价格、数量差异或缺少审批等原因。 | ||
为何重要 这是问题和返工的关键指标。分析冻结原因和持续时间有助于识别付款延迟和流程低效的根本原因。 获取方式 这是一个明确的状态,记录在会计凭证 (表 BSEG) 的供应商行项目上的“付款冻结键”字段 (ZLSPR) 中。 捕获 当 BSEG-ZLSPR 字段中填入冻结原因时,通过更改凭证进行记录。 事件类型 explicit | |||
发票已取消 | 该发票单据已被冲销,有效消除了其财务影响。这是一种替代的流程终结状态,通常是由于错误的录入或供应商争议所致。 | ||
为何重要 追踪取消操作有助于识别流程失败的原因,例如重复提交或不正确的发票数据,这可能指向上游问题。 获取方式 当冲销凭证被创建时,此信息会被明确记录。原始凭证抬头 (BKPF) 中将填入冲销凭证号 (STBLG) 和冲销原因。 捕获 识别冲销凭证的过账日期,该日期链接在原始凭证的抬头 (BKPF-STBLG) 中。 事件类型 explicit | |||
发票已批准 | 该发票已在 workflow 系统中获得所有必要的审批。这通常是发票过账或解除付款冻结前的最后一步。 | ||
为何重要 这一关键里程碑标志着审批周期的结束。从分发到审批之间的时间是衡量效率的关键指标。 获取方式 可从SAP业务Workflow日志中捕获,作为完成或最终发布步骤。此外,也可通过付款路由后移除付款冻结来推断此信息。 捕获 从 SAP 工作流日志中提取工作流完成事件,或识别最终的 'release' 事件。 事件类型 explicit | |||
发票已过账 | 该发票正式记录在总账中,产生一项财务负债。暂存凭证会成为过账凭证,或者直接进行过账。 | ||
为何重要 这是一个关键的财务里程碑。它确认了公司的付款义务,通常是安排付款的先决条件。 获取方式 此 event (事件) 由凭证 header (抬头) (BKPF) 中的过账日期 (BUDAT) 识别。已过账凭证的凭证状态 (BKPF-BSTAT) 为空白。 捕获 对于未暂存的凭证(BKPF-BSTAT 为空),使用过账时间戳 (BKPF-BUDAT)。 事件类型 explicit | |||
发票收到 | 此活动标志着在 SAP 中创建发票凭证,可通过手动或 OCR/VIM 等自动化接口完成。此 event (事件) 通常从会计凭证 header (抬头) 的创建日期和时间中捕获。 | ||
为何重要 作为流程的起点,此活动对于计算端到端发票周期时间,以及衡量整个应付账款(AP)流程的吞吐量至关重要。 获取方式 此 event (事件) 是从会计凭证 header (抬头) 表 (BKPF) 中,使用凭证创建日期 (CPUDT) 和时间 (CPUTM) 捕获的。 捕获 使用发票凭证的创建时间戳(BKPF-CPUDT, BKPF-CPUTM)。 事件类型 explicit | |||
已执行付款 | 发票已收到付款。这通常在付款运行完成、并创建和过账付款凭证时被记录。 | ||
为何重要 此活动对于现金流分析至关重要,通过将该日期与发票到期日进行比较,可以衡量“准时付款率”这一 KPI。 获取方式 这从结清发票的付款凭证的过账日期捕获。付款凭证编号链接在发票行项目 (BSEG) 的结清凭证字段 (AUGBL) 中。 捕获 识别清算发票行项目的付款凭证的过账日期 (BUDAT)。 事件类型 explicit | |||
付款建议已创建 | 该发票已作为付款运行(例如 F110)的一部分,包含在付款建议中。目前已预定付款,等待运行的最终执行。 | ||
为何重要 此活动显示了从一项未结负债转变为一项正在积极准备支付的款项,有助于分析支付操作的效率。 获取方式 此 event (事件) 明确记录在付款运行 data (数据) 表中,具体是 REGUP (支付程序处理项目) 和 REGUH (Header)。 捕获 识别发票何时出现在 REGUP 表中,并与 REGUH 中标识的付款运行相对应。 事件类型 explicit | |||
发票到期日已过 | 这是一个计算事件,表明发票的净到期日已过,但尚未收到付款。这表示付款已逾期。 | ||
为何重要 对于“付款合规与账龄”Dashboard 至关重要,此活动有助于主动识别和管理逾期发票,并分析逾期付款的根本原因。 获取方式 这在 SAP 中并非一个显性事件。它是通过将系统当前日期与净到期日(根据 BSEG-ZFBDT 或基准日期和付款条款计算得出)进行比较来计算的。 捕获 当Event 时间戳大于发票净到期日时触发的计算Event。 事件类型 calculated | |||
发票已拒绝 | 审批人在审批工作流中拒绝了发票。此操作通常会将发票退回给处理人进行更正或澄清。 | ||
为何重要 追踪拒绝情况有助于揭示审批流程中的返工环节,并可能表明政策合规性或发票编码不正确的问题。 获取方式 这作为与发票关联的 SAP Business Workflow 日志中的一个特定结果 event (事件) 被捕获。 捕获 从 SAP 工作流日志中提取 'rejected' 状态的工作流事件。 事件类型 explicit | |||
发票已暂存 | 指的是发票已输入系统但尚未过账到总账。这通常是刻意为之的步骤,旨在保存未完成的单据,以便后续处理或审批。 | ||
为何重要 追踪暂存发票有助于识别正式过账流程开始前的延迟,并能突出数据完整性或初始验证方面的问题。 获取方式 此状态根据会计凭证抬头中的凭证状态字段(BKPF-BSTAT = 'V' 表示暂存)推断得出。该事件在状态被设置时发生。 捕获 识别表 BKPF 中 BSTAT 字段设置为 'V'(预录入/Pre-entered)的更改凭证。 事件类型 inferred | |||
发票已送审 | 该发票已根据业务规则提交至 workflow 以进行必要的审批。这标志着审批子流程的开始。 | ||
为何重要 此活动是衡量“平均发票审批时间”这一 KPI 和分析审批瓶颈的起点。 获取方式 可从SAP业务Workflow日志(SWW*表)中捕获。这些日志记录了与发票对象(例如BUS2081)关联的Workflow实例的启动。 捕获 从与发票凭证关联的 SAP 工作流日志 (例如表 SWW_WIHEAD) 中提取工作流启动事件。 事件类型 explicit | |||
差异已解决 | 此活动表明,先前识别出的可能导致付款冻结的问题已得到调查和解决。当发票的付款冻结被移除时,即记录此活动。 | ||
为何重要 追踪此返工循环对于“发票差异返工分析”仪表盘至关重要。它有助于量化纠正错误所花费的时间和精力。 获取方式 此信息通过显示移除付款冻结的变更凭证推断得出。BSEG-ZLSPR 字段的变更日志是主要来源。 捕获 识别表 BSEG 中 ZLSPR 字段从有值变为空白的更改凭证。 事件类型 inferred | |||
收货已匹配 | 此活动标志着发票的数量和金额已成功匹配到相应的收货凭证。这是 3-way matching (三方匹配) 场景中的最终验证步骤。 | ||
为何重要 追踪此项有助于查明三方匹配流程中的低效之处,并识别收货与供应商开票之间存在的差异。 获取方式 此信息通过发票行项目中存在的物料凭证参考(收货)推断得出,通常通过采购订单项目历史记录进行关联。 捕获 从发票行项目上存在收货凭证引用(例如,MIRO 发票的 RSEG 中)推断得出。 事件类型 inferred | |||
采购订单已匹配 | 此活动标志着发票已成功匹配到相应的采购订单。这是基于采购的发票在 3-way matching (三方匹配) 流程中的关键一步。 | ||
为何重要 深入分析此活动,有助于衡量匹配流程的效率,更是“三向匹配绩效”和“无采购订单发票比例”这两项关键绩效指标(KPI)的基石。 获取方式 当表 BSEG 或 ACDOCA 中的发票行项目包含有效的采购订单号 (EBELN) 和项目 (EBELP) 时,此信息可被推断。 捕获 从创建发票凭证时存在采购订单引用(BSEG-EBELN)推断得出。 事件类型 inferred | |||
提取指南
步骤
- 前提条件和访问权限:请确保您拥有一个对 SAP S/4HANA 数据库架构(通常为 SAPABAP1 或类似名称)具有读取权限的用户,并且该架构中包含所需的 CDS 视图。您还需要一个能够连接到 SAP HANA 数据库的 SQL 客户端工具,例如 SAP HANA Studio、DBeaver 等数据库查询工具。
- 识别核心 CDS 视图:用于本次数据提取的主要 CDS 视图包括 I_JournalEntry、I_JournalEntryItem、I_SupplierInvoiceAPI01、I_ChangeDocument、I_WorkflowStatusDetails 和 I_PaymentProposalItem。请熟悉它们的关键字段。
- 定义查询范围:打开您的 SQL 客户端并连接到 SAP HANA 数据库。在运行完整查询之前,请定义您的数据提取范围。这包括设置正确的源系统标识符、发票的日期范围 (CreationDateTime) 以及要分析的公司代码。
- 准备主查询:将 query 部分提供的完整 SQL 查询复制到您的 SQL 客户端中。该查询使用公用表表达式 (CTEs) 首先选择发票的基础数据集,然后通过整合 15 种不同活动的数据来构建一个事件日志。
- 设置查询参数:在复制的 SQL 查询中,找到占位符变量。将 '[YYYY-MM-DD]' 替换为您分析期间的开始和结束日期。将 '[Your Company Code 1]', '[Your Company Code 2]' 替换为您希望分析的 SAP 公司代码列表。
- 执行提取查询:运行完整的 SQL 查询。根据数据量和选定的日期范围,这可能需要几分钟到数小时才能完成。
- 审查初步结果:查询完成后,请审查输出的前几百行。检查数据一致性,确保所有列都按预期填充,并验证 ActivityName 列中包含不同类型的值。
- 导出事件日志:将 SQL 客户端中的整个结果集导出为 CSV 文件。确保文件采用 UTF-8 编码,以防止字符问题。描述性地命名文件,例如 sap_s4hana_ap_event_log.csv。
- 准备上传:在上传到流程挖掘工具之前,请确认 CSV 文件中的列标题与所需的属性名称完全匹配:Invoice、ActivityName、EventTime、SourceSystem、LastDataUpdate、UserName 等。
- 上传到流程挖掘工具:将生成的 CSV 文件上传到您的流程挖掘平台,并将列映射到对应的案例ID、活动和时间戳字段。
配置
- 关键CDS视图:数据提取主要依赖于标准的S/4HANA CDS视图组合。主要视图包括:
- I_JournalEntry 和 I_JournalEntryItem:用于核心财务凭证的抬头、项目、过账明细及清账信息。
- I_SupplierInvoiceAPI01:用于MM(物流)发票的具体信息,包括采购订单参照和付款冻结情况。
- I_ChangeDocument:用于追踪变更的精确时间戳,例如设置或移除付款冻结。
- I_WorkflowStatusDetails:用于提取与发票审批工作流相关的事件。
- I_PaymentProposalItem:用于识别发票何时被包含在付款运行建议中。
- I_Supplier:通过供应商主数据信息(如 VendorName)来丰富数据。
- 日期范围过滤:应用日期范围过滤器以限制数据量至关重要。提供的查询是在Invoices_Base CTE中对CreationDateTime进行过滤。建议初始分析使用3-6个月的数据范围,以确保性能可控。
- 强制性过滤器:始终按CompanyCode进行过滤。一次性分析所有公司代码的数据可能非常缓慢,并且可能与业务不直接相关。此外,还需按JournalEntryType进行过滤,以仅选择与供应商相关的凭证(例如,'KR','RE')。
- 前提条件:执行数据库的用户必须对查询中使用的所有CDS视图以及底层的HANA schema具有SELECT权限。仅拥有SAP GUI中的应用层访问权限是不够的。
- 性能考量:直接查询I_ChangeDocument可能会消耗大量资源。提供的查询通过首先预过滤发票来尝试缓解此问题。对于非常大的数据集,建议在非高峰时段或分批次(较小的日期范围)运行数据提取。
a 查询示例 sql
`sql
-- Common Table Expression (CTE) to select the base set of AP Invoices
WITH Invoices_Base AS (
SELECT
I_JournalEntry.CompanyCode,
I_JournalEntry.AccountingDocument,
I_JournalEntry.FiscalYear,
CONCAT(I_JournalEntry.CompanyCode, CONCAT(I_JournalEntry.AccountingDocument, I_JournalEntry.FiscalYear)) AS InvoiceId,
I_JournalEntry.CreationDateTime,
I_JournalEntry.CreatedByUser,
I_JournalEntry.DocumentStatus,
I_JournalEntry.JournalEntryType,
I_JournalEntry.ReversalReferenceJournalEntry,
I_JournalEntry.IsReversed,
I_JournalEntry.ReversalDate,
IJE_ITEM.NetDueDate,
IJE_ITEM.Supplier,
SUP.SupplierName AS VendorName,
IJE_ITEM.AmountInCompanyCodeCurrency AS InvoiceAmount,
MM.PurchaseOrder AS PurchaseOrderNumber,
MM.PaymentBlockingReason
FROM I_JournalEntry
-- Join to get item details like due date and supplier
LEFT JOIN I_JournalEntryItem AS IJE_ITEM
ON I_JournalEntry.CompanyCode = IJE_ITEM.CompanyCode
AND I_JournalEntry.AccountingDocument = IJE_ITEM.AccountingDocument
AND I_JournalEntry.FiscalYear = IJE_ITEM.FiscalYear
AND IJE_ITEM.IsSupplier = 'X'
-- Join to get vendor name from master data
LEFT JOIN I_Supplier AS SUP
ON IJE_ITEM.Supplier = SUP.Supplier
-- Join to get MM Invoice specific data like PO Number and Payment Block
LEFT JOIN I_SupplierInvoiceAPI01 AS MM
ON I_JournalEntry.AccountingDocument = MM.AccountingDocument
AND I_JournalEntry.CompanyCode = MM.CompanyCode
AND I_JournalEntry.FiscalYear = MM.FiscalYear
WHERE
I_JournalEntry.JournalEntryType IN ('KR', 'RE') -- Standard Vendor Invoice Types
AND I_JournalEntry.CompanyCode IN ('[Your Company Code 1]', '[Your Company Code 2]')
AND I_JournalEntry.CreationDateTime BETWEEN '[YYYY-MM-DD]T00:00:00Z' AND '[YYYY-MM-DD]T23:59:59Z'
)
-- Event: 1. Invoice Received
SELECT
B.InvoiceId AS "Invoice",
'Invoice Received' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
UNION ALL
-- Event: 2. Invoice Parked
SELECT
B.InvoiceId AS "Invoice",
'Invoice Parked' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.DocumentStatus = 'V' -- 'V' stands for Parked
UNION ALL
-- Event: 3. Purchase Order Matched
SELECT
B.InvoiceId AS "Invoice",
'Purchase Order Matched' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.PurchaseOrderNumber IS NOT NULL AND B.PurchaseOrderNumber <> ''
UNION ALL
-- Event: 4. Goods Receipt Matched
SELECT
B.InvoiceId AS "Invoice",
'Goods Receipt Matched' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_SupplierInvoiceItemAPI01 AS MM_ITEM
ON B.AccountingDocument = MM_ITEM.AccountingDocument
AND B.FiscalYear = MM_ITEM.FiscalYear
WHERE MM_ITEM.GoodsReceipt IS NOT NULL AND MM_ITEM.GoodsReceipt <> ''
UNION ALL
-- Event: 5. Invoice Blocked For Payment
SELECT
B.InvoiceId AS "Invoice",
'Invoice Blocked For Payment' AS "ActivityName",
B.CreationDateTime AS "EventTime", -- Approximates block time as creation time if blocked on entry
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.PaymentBlockingReason IS NOT NULL AND B.PaymentBlockingReason <> ''
UNION ALL
-- Event: 6. Discrepancy Resolved (Payment Block Removed)
SELECT
B.InvoiceId AS "Invoice",
'Discrepancy Resolved' AS "ActivityName",
CD.ChangeTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
CD.UserName AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_ChangeDocument AS CD
ON CONCAT(B.CompanyCode, B.AccountingDocument, B.FiscalYear) = CD.ObjectValue
WHERE CD.ChangeDocumentObject = 'INVOICE'
AND CD.TableName = 'RBKP'
AND CD.FieldName = 'ZLSPR' -- Field for Payment Block
AND CD.NewFieldValue = '' -- Block was removed
UNION ALL
-- Event: 7, 8, 9. Workflow Events (Routed, Approved, Rejected)
SELECT
B.InvoiceId AS "Invoice",
CASE WF.WorkflowStatus
WHEN 'READY' THEN 'Invoice Routed For Approval'
WHEN 'APPROVED' THEN 'Invoice Approved'
WHEN 'REJECTED' THEN 'Invoice Rejected'
END AS "ActivityName",
WF.WorkflowStatusChangedDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
WF.WorkflowStatusChangedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_WorkflowStatusDetails AS WF
ON B.InvoiceId = WF.WorkflowScenarioInstance
WHERE WF.WorkflowStatus IN ('READY', 'APPROVED', 'REJECTED')
UNION ALL
-- Event: 10. Invoice Posted
SELECT
B.InvoiceId AS "Invoice",
'Invoice Posted' AS "ActivityName",
JE.PostingDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_JournalEntry AS JE
ON B.AccountingDocument = JE.AccountingDocument
AND B.CompanyCode = JE.CompanyCode
AND B.FiscalYear = JE.FiscalYear
WHERE B.DocumentStatus <> 'V' -- Any status other than Parked is considered Posted for AP
UNION ALL
-- Event: 11. Payment Proposal Created
SELECT
B.InvoiceId AS "Invoice",
'Payment Proposal Created' AS "ActivityName",
PPI.PaymentProposalRunDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
PPI.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_PaymentProposalItem AS PPI
ON B.CompanyCode = PPI.CompanyCode
AND B.AccountingDocument = PPI.AccountingDocument
AND B.FiscalYear = PPI.FiscalYear
UNION ALL
-- Event: 12. Payment Executed
-- This links the invoice to its clearing document, which is the payment document
SELECT DISTINCT
B.InvoiceId AS "Invoice",
'Payment Executed' AS "ActivityName",
CLEAR_JE.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
CLEAR_JE.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_JournalEntryItem AS IJE_ITEM
ON B.CompanyCode = IJE_ITEM.CompanyCode
AND B.AccountingDocument = IJE_ITEM.AccountingDocument
AND B.FiscalYear = IJE_ITEM.FiscalYear
INNER JOIN I_JournalEntry AS CLEAR_JE
ON IJE_ITEM.ClearingJournalEntry = CLEAR_JE.AccountingDocument
AND IJE_ITEM.CompanyCode = CLEAR_JE.CompanyCode
WHERE IJE_ITEM.ClearingJournalEntry IS NOT NULL AND IJE_ITEM.ClearingJournalEntry <> ''
AND CLEAR_JE.JournalEntryType = 'KZ' -- Vendor Payment Document Type
UNION ALL
-- Event: 13. Invoice Due Date Passed
SELECT
B.InvoiceId AS "Invoice",
'Invoice Due Date Passed' AS "ActivityName",
ADD_DAYS(B.NetDueDate, 1) AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
'SYSTEM' AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
LEFT JOIN I_JournalEntryItem AS IJE_ITEM
ON B.CompanyCode = IJE_ITEM.CompanyCode
AND B.AccountingDocument = IJE_ITEM.AccountingDocument
AND B.FiscalYear = IJE_ITEM.FiscalYear
WHERE B.NetDueDate < CURRENT_DATE
AND IJE_ITEM.ClearingDate IS NULL -- Invoice is not yet cleared
UNION ALL
-- Event: 14. Payment Cleared
SELECT DISTINCT
B.InvoiceId AS "Invoice",
'Payment Cleared' AS "ActivityName",
IJE_ITEM.ClearingDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
IJE_ITEM.ChangedByUser AS "UserName", -- User who cleared it
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_JournalEntryItem AS IJE_ITEM
ON B.CompanyCode = IJE_ITEM.CompanyCode
AND B.AccountingDocument = IJE_ITEM.AccountingDocument
AND B.FiscalYear = IJE_ITEM.FiscalYear
WHERE IJE_ITEM.ClearingDate IS NOT NULL
UNION ALL
-- Event: 15. Invoice Cancelled
SELECT
B.InvoiceId AS "Invoice",
'Invoice Cancelled' AS "ActivityName",
B.ReversalDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName", -- User who created the original document
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.IsReversed = 'X';
`步骤
- 前提条件和访问权限:请确保您拥有一个对 SAP S/4HANA 数据库架构(通常为 SAPABAP1 或类似名称)具有读取权限的用户,并且该架构中包含所需的 CDS 视图。您还需要一个能够连接到 SAP HANA 数据库的 SQL 客户端工具,例如 SAP HANA Studio、DBeaver 等数据库查询工具。
- 识别核心 CDS 视图:用于本次数据提取的主要 CDS 视图包括 I_JournalEntry、I_JournalEntryItem、I_SupplierInvoiceAPI01、I_ChangeDocument、I_WorkflowStatusDetails 和 I_PaymentProposalItem。请熟悉它们的关键字段。
- 定义查询范围:打开您的 SQL 客户端并连接到 SAP HANA 数据库。在运行完整查询之前,请定义您的数据提取范围。这包括设置正确的源系统标识符、发票的日期范围 (CreationDateTime) 以及要分析的公司代码。
- 准备主查询:将 query 部分提供的完整 SQL 查询复制到您的 SQL 客户端中。该查询使用公用表表达式 (CTEs) 首先选择发票的基础数据集,然后通过整合 15 种不同活动的数据来构建一个事件日志。
- 设置查询参数:在复制的 SQL 查询中,找到占位符变量。将 '[YYYY-MM-DD]' 替换为您分析期间的开始和结束日期。将 '[Your Company Code 1]', '[Your Company Code 2]' 替换为您希望分析的 SAP 公司代码列表。
- 执行提取查询:运行完整的 SQL 查询。根据数据量和选定的日期范围,这可能需要几分钟到数小时才能完成。
- 审查初步结果:查询完成后,请审查输出的前几百行。检查数据一致性,确保所有列都按预期填充,并验证 ActivityName 列中包含不同类型的值。
- 导出事件日志:将 SQL 客户端中的整个结果集导出为 CSV 文件。确保文件采用 UTF-8 编码,以防止字符问题。描述性地命名文件,例如 sap_s4hana_ap_event_log.csv。
- 准备上传:在上传到流程挖掘工具之前,请确认 CSV 文件中的列标题与所需的属性名称完全匹配:Invoice、ActivityName、EventTime、SourceSystem、LastDataUpdate、UserName 等。
- 上传到流程挖掘工具:将生成的 CSV 文件上传到您的流程挖掘平台,并将列映射到对应的案例ID、活动和时间戳字段。
配置
- 关键CDS视图:数据提取主要依赖于标准的S/4HANA CDS视图组合。主要视图包括:
- I_JournalEntry 和 I_JournalEntryItem:用于核心财务凭证的抬头、项目、过账明细及清账信息。
- I_SupplierInvoiceAPI01:用于MM(物流)发票的具体信息,包括采购订单参照和付款冻结情况。
- I_ChangeDocument:用于追踪变更的精确时间戳,例如设置或移除付款冻结。
- I_WorkflowStatusDetails:用于提取与发票审批工作流相关的事件。
- I_PaymentProposalItem:用于识别发票何时被包含在付款运行建议中。
- I_Supplier:通过供应商主数据信息(如 VendorName)来丰富数据。
- 日期范围过滤:应用日期范围过滤器以限制数据量至关重要。提供的查询是在Invoices_Base CTE中对CreationDateTime进行过滤。建议初始分析使用3-6个月的数据范围,以确保性能可控。
- 强制性过滤器:始终按CompanyCode进行过滤。一次性分析所有公司代码的数据可能非常缓慢,并且可能与业务不直接相关。此外,还需按JournalEntryType进行过滤,以仅选择与供应商相关的凭证(例如,'KR','RE')。
- 前提条件:执行数据库的用户必须对查询中使用的所有CDS视图以及底层的HANA schema具有SELECT权限。仅拥有SAP GUI中的应用层访问权限是不够的。
- 性能考量:直接查询I_ChangeDocument可能会消耗大量资源。提供的查询通过首先预过滤发票来尝试缓解此问题。对于非常大的数据集,建议在非高峰时段或分批次(较小的日期范围)运行数据提取。
a 查询示例 sql
`sql
-- Common Table Expression (CTE) to select the base set of AP Invoices
WITH Invoices_Base AS (
SELECT
I_JournalEntry.CompanyCode,
I_JournalEntry.AccountingDocument,
I_JournalEntry.FiscalYear,
CONCAT(I_JournalEntry.CompanyCode, CONCAT(I_JournalEntry.AccountingDocument, I_JournalEntry.FiscalYear)) AS InvoiceId,
I_JournalEntry.CreationDateTime,
I_JournalEntry.CreatedByUser,
I_JournalEntry.DocumentStatus,
I_JournalEntry.JournalEntryType,
I_JournalEntry.ReversalReferenceJournalEntry,
I_JournalEntry.IsReversed,
I_JournalEntry.ReversalDate,
IJE_ITEM.NetDueDate,
IJE_ITEM.Supplier,
SUP.SupplierName AS VendorName,
IJE_ITEM.AmountInCompanyCodeCurrency AS InvoiceAmount,
MM.PurchaseOrder AS PurchaseOrderNumber,
MM.PaymentBlockingReason
FROM I_JournalEntry
-- Join to get item details like due date and supplier
LEFT JOIN I_JournalEntryItem AS IJE_ITEM
ON I_JournalEntry.CompanyCode = IJE_ITEM.CompanyCode
AND I_JournalEntry.AccountingDocument = IJE_ITEM.AccountingDocument
AND I_JournalEntry.FiscalYear = IJE_ITEM.FiscalYear
AND IJE_ITEM.IsSupplier = 'X'
-- Join to get vendor name from master data
LEFT JOIN I_Supplier AS SUP
ON IJE_ITEM.Supplier = SUP.Supplier
-- Join to get MM Invoice specific data like PO Number and Payment Block
LEFT JOIN I_SupplierInvoiceAPI01 AS MM
ON I_JournalEntry.AccountingDocument = MM.AccountingDocument
AND I_JournalEntry.CompanyCode = MM.CompanyCode
AND I_JournalEntry.FiscalYear = MM.FiscalYear
WHERE
I_JournalEntry.JournalEntryType IN ('KR', 'RE') -- Standard Vendor Invoice Types
AND I_JournalEntry.CompanyCode IN ('[Your Company Code 1]', '[Your Company Code 2]')
AND I_JournalEntry.CreationDateTime BETWEEN '[YYYY-MM-DD]T00:00:00Z' AND '[YYYY-MM-DD]T23:59:59Z'
)
-- Event: 1. Invoice Received
SELECT
B.InvoiceId AS "Invoice",
'Invoice Received' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
UNION ALL
-- Event: 2. Invoice Parked
SELECT
B.InvoiceId AS "Invoice",
'Invoice Parked' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.DocumentStatus = 'V' -- 'V' stands for Parked
UNION ALL
-- Event: 3. Purchase Order Matched
SELECT
B.InvoiceId AS "Invoice",
'Purchase Order Matched' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.PurchaseOrderNumber IS NOT NULL AND B.PurchaseOrderNumber <> ''
UNION ALL
-- Event: 4. Goods Receipt Matched
SELECT
B.InvoiceId AS "Invoice",
'Goods Receipt Matched' AS "ActivityName",
B.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_SupplierInvoiceItemAPI01 AS MM_ITEM
ON B.AccountingDocument = MM_ITEM.AccountingDocument
AND B.FiscalYear = MM_ITEM.FiscalYear
WHERE MM_ITEM.GoodsReceipt IS NOT NULL AND MM_ITEM.GoodsReceipt <> ''
UNION ALL
-- Event: 5. Invoice Blocked For Payment
SELECT
B.InvoiceId AS "Invoice",
'Invoice Blocked For Payment' AS "ActivityName",
B.CreationDateTime AS "EventTime", -- Approximates block time as creation time if blocked on entry
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.PaymentBlockingReason IS NOT NULL AND B.PaymentBlockingReason <> ''
UNION ALL
-- Event: 6. Discrepancy Resolved (Payment Block Removed)
SELECT
B.InvoiceId AS "Invoice",
'Discrepancy Resolved' AS "ActivityName",
CD.ChangeTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
CD.UserName AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_ChangeDocument AS CD
ON CONCAT(B.CompanyCode, B.AccountingDocument, B.FiscalYear) = CD.ObjectValue
WHERE CD.ChangeDocumentObject = 'INVOICE'
AND CD.TableName = 'RBKP'
AND CD.FieldName = 'ZLSPR' -- Field for Payment Block
AND CD.NewFieldValue = '' -- Block was removed
UNION ALL
-- Event: 7, 8, 9. Workflow Events (Routed, Approved, Rejected)
SELECT
B.InvoiceId AS "Invoice",
CASE WF.WorkflowStatus
WHEN 'READY' THEN 'Invoice Routed For Approval'
WHEN 'APPROVED' THEN 'Invoice Approved'
WHEN 'REJECTED' THEN 'Invoice Rejected'
END AS "ActivityName",
WF.WorkflowStatusChangedDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
WF.WorkflowStatusChangedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_WorkflowStatusDetails AS WF
ON B.InvoiceId = WF.WorkflowScenarioInstance
WHERE WF.WorkflowStatus IN ('READY', 'APPROVED', 'REJECTED')
UNION ALL
-- Event: 10. Invoice Posted
SELECT
B.InvoiceId AS "Invoice",
'Invoice Posted' AS "ActivityName",
JE.PostingDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_JournalEntry AS JE
ON B.AccountingDocument = JE.AccountingDocument
AND B.CompanyCode = JE.CompanyCode
AND B.FiscalYear = JE.FiscalYear
WHERE B.DocumentStatus <> 'V' -- Any status other than Parked is considered Posted for AP
UNION ALL
-- Event: 11. Payment Proposal Created
SELECT
B.InvoiceId AS "Invoice",
'Payment Proposal Created' AS "ActivityName",
PPI.PaymentProposalRunDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
PPI.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_PaymentProposalItem AS PPI
ON B.CompanyCode = PPI.CompanyCode
AND B.AccountingDocument = PPI.AccountingDocument
AND B.FiscalYear = PPI.FiscalYear
UNION ALL
-- Event: 12. Payment Executed
-- This links the invoice to its clearing document, which is the payment document
SELECT DISTINCT
B.InvoiceId AS "Invoice",
'Payment Executed' AS "ActivityName",
CLEAR_JE.CreationDateTime AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
CLEAR_JE.CreatedByUser AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_JournalEntryItem AS IJE_ITEM
ON B.CompanyCode = IJE_ITEM.CompanyCode
AND B.AccountingDocument = IJE_ITEM.AccountingDocument
AND B.FiscalYear = IJE_ITEM.FiscalYear
INNER JOIN I_JournalEntry AS CLEAR_JE
ON IJE_ITEM.ClearingJournalEntry = CLEAR_JE.AccountingDocument
AND IJE_ITEM.CompanyCode = CLEAR_JE.CompanyCode
WHERE IJE_ITEM.ClearingJournalEntry IS NOT NULL AND IJE_ITEM.ClearingJournalEntry <> ''
AND CLEAR_JE.JournalEntryType = 'KZ' -- Vendor Payment Document Type
UNION ALL
-- Event: 13. Invoice Due Date Passed
SELECT
B.InvoiceId AS "Invoice",
'Invoice Due Date Passed' AS "ActivityName",
ADD_DAYS(B.NetDueDate, 1) AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
'SYSTEM' AS "UserName",
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
LEFT JOIN I_JournalEntryItem AS IJE_ITEM
ON B.CompanyCode = IJE_ITEM.CompanyCode
AND B.AccountingDocument = IJE_ITEM.AccountingDocument
AND B.FiscalYear = IJE_ITEM.FiscalYear
WHERE B.NetDueDate < CURRENT_DATE
AND IJE_ITEM.ClearingDate IS NULL -- Invoice is not yet cleared
UNION ALL
-- Event: 14. Payment Cleared
SELECT DISTINCT
B.InvoiceId AS "Invoice",
'Payment Cleared' AS "ActivityName",
IJE_ITEM.ClearingDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
IJE_ITEM.ChangedByUser AS "UserName", -- User who cleared it
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
INNER JOIN I_JournalEntryItem AS IJE_ITEM
ON B.CompanyCode = IJE_ITEM.CompanyCode
AND B.AccountingDocument = IJE_ITEM.AccountingDocument
AND B.FiscalYear = IJE_ITEM.FiscalYear
WHERE IJE_ITEM.ClearingDate IS NOT NULL
UNION ALL
-- Event: 15. Invoice Cancelled
SELECT
B.InvoiceId AS "Invoice",
'Invoice Cancelled' AS "ActivityName",
B.ReversalDate AS "EventTime",
'SAP_S4HANA' AS "SourceSystem",
CURRENT_UTCTIMESTAMP AS "LastDataUpdate",
B.CreatedByUser AS "UserName", -- User who created the original document
B.CompanyCode AS "CompanyCode",
B.VendorName AS "VendorName",
B.InvoiceAmount AS "InvoiceAmount",
B.PurchaseOrderNumber AS "PurchaseOrderNumber",
B.NetDueDate AS "InvoiceDueDate"
FROM Invoices_Base B
WHERE B.IsReversed = 'X';
`步骤
- 需求与设计:编码前,与业务分析师确认15项必需活动的触发条件和所需数据字段;同时明确本次范围内的SAP相关表、凭证类型(如“KR”“RE”)以及公司代码。
- 创建ABAP程序:使用事务码SE38打开ABAP编辑器,新建可执行程序(如Z_PM_AP_INVOICE_EXTRACT),填写清晰的标题,并将应用设置为“财务会计”。
- 定义选择屏幕:在程序中使用PARAMETERS和SELECT-OPTIONS定义选择屏幕,允许用户指定提取的日期范围(按发票创建日期)、目标公司代码(BUKRS)及相关发票凭证类型(BLART),并增加一个参数用于指定应用服务器上的输出文件路径。
- 数据声明:定义与最终事件日志格式一致的内部表结构(如TY_EVENT_LOG),包含所有必填和建议的属性。声明内部表用于存放从BKPF、BSEG、RBKP、RSEG、CDHDR、CDPOS、REGUH等源表选取的数据。
- 主要数据选择:根据选择屏幕的条件,从RBKP(物流发票)和BKPF(财务发票)选出符合条件的发票,作为主数据集。将这些发票的主键存入内部表,用于驱动后续的数据查找。
- 按序提取活动:对主数据集中的每张发票,依次查询各业务活动的时间戳和明细。例如:查询CDHDR、CDPOS获取付款阻止变更,查询REGUH、REGUP获取付款运行数据,查询BKPF获取冲销凭证信息。每发现一个活动,向最终事件日志表追加一条记录。
- 计算类事件逻辑:为未直接存储在表字段中的活动编写ABAP逻辑。以“发票到期日已过”为例,使用发票到期日(BSEG-ZFBDT+付款条件)和清账日期(BSEG-AUGDT)进行判断;若清账日期晚于到期日,则新增一条事件记录,并将时间戳设为到期日。
- 数据转换与丰富:在汇集各活动数据时,补齐所有必填属性,例如从LFA1获取供应商名称;将日期和时间拼接为单一的时间戳字符串(CONCATENATE...INTO...);并设置SourceSystem值。
- 生成输出文件:当所有发票及其对应活动处理完成并汇总至最终内部表后,使用OPEN DATASET、LOOP AT ... TRANSFER、CLOSE DATASET语句,将数据写入选择屏幕指定路径的应用服务器文件。
- 下载并准备上传:使用事务码CG3Y将生成的文件从应用服务器下载到本地,保存为UTF-8编码的CSV。上传至流程挖掘工具前,核对列头是否与所需属性一致(Invoice、ActivityName、EventTime等)。
配置
- 日期范围:为发票创建日期定义P_CPUDT选择选项(BKPF-CPUDT或RBKP-CPUDT)。建议先抽取6–12个月的数据进行初步分析。
- 公司代码(P_BUKRS):必填的SELECT-OPTIONS参数,用于按公司代码筛选。除非确有必要,不建议一次性处理所有公司代码。
- 发票凭证类型(P_BLART):用于筛选相关发票凭证类型的SELECT-OPTIONS参数。常见类型包括“KR”(供应商发票)、“KG”(供应商贷项通知单)、“RE”(物流发票校验)。
- 执行模式:大数据量时应作为后台作业(SM36/SM37)运行,避免前台对话超时,并安排在业务低峰期执行。
- 输出文件路径:通过PARAMETER指定SAP应用服务器上的文件路径与文件名(例如/tmp/目录)。文件将先写入该位置,再供下载。
- 先决条件:执行报表的用户需具备读取FI、CO、MM表(BKPF、BSEG、RBKP、RSEG、LFA1)、变更文档表(CDHDR、CDPOS)以及Workflow表的权限;此外还需要授权对象S_DATASET,以便在应用服务器上写入文件。
a 查询示例 abap
`abap
*&---------------------------------------------------------------------*
*& Report Z_PM_AP_INVOICE_EXTRACT
*&---------------------------------------------------------------------*
*& This report extracts Accounts Payable invoice lifecycle events for
*& process mining analysis.
*&---------------------------------------------------------------------*
REPORT z_pm_ap_invoice_extract.
*&---------------------------------------------------------------------*
*& Data Structures
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
invoice TYPE belnr_d,
activityname TYPE string,
eventtime TYPE string,
sourcesystem TYPE logsys,
lastdataupdate TYPE string,
username TYPE uname,
companycode TYPE bukrs,
vendorname TYPE name1_gp,
invoiceamount TYPE wrbtr,
purchaseordernumber TYPE ebeln,
invoiceduedate TYPE d,
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
DATA: gv_system_id TYPE logsys.
DATA: gv_last_update TYPE string.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_bukrs FOR bkpf-bukrs OBLIGATORY,
s_cpudt FOR bkpf-cpudt OBLIGATORY DEFAULT sy-datum,
s_blart FOR bkpf-blart.
PARAMETERS: p_fpath TYPE string OBLIGATORY DEFAULT '/tmp/ap_extract.csv'.
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
" Get System ID and Update Timestamp
CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET'
IMPORTING
own_logical_system = gv_system_id
EXCEPTIONS
own_logical_system_not_defined = 1
OTHERS = 2.
CONCATENATE sy-datum sy-uzeit INTO gv_last_update.
" Internal tables for SAP data
DATA: lt_bkpf TYPE TABLE OF bkpf,
lt_rbkp TYPE TABLE OF rbkp.
" Select base documents
SELECT * FROM bkpf INTO TABLE lt_bkpf
WHERE bukrs IN s_bukrs
AND cpudt IN s_cpudt
AND blart IN s_blart
AND ( blart = 'KR' OR blart = 'KG' ). " Example FI Invoice Types
SELECT * FROM rbkp INTO TABLE lt_rbkp
WHERE bukrs IN s_bukrs
AND cpudt IN s_cpudt
AND blart IN s_blart
AND blart = 'RE'. " Example MM Invoice Type
" --- Process each invoice document ---
LOOP AT lt_bkpf ASSIGNING FIELD-SYMBOL(<fs_bkpf>).
PERFORM process_invoice USING <fs_bkpf>.
ENDLOOP.
LOOP AT lt_rbkp ASSIGNING FIELD-SYMBOL(<fs_rbkp>).
PERFORM process_mm_invoice USING <fs_rbkp>.
ENDLOOP.
" Write output to file
PERFORM write_output_file.
*&---------------------------------------------------------------------*
*& Form PROCESS_INVOICE (Handles FI Invoices)
*&---------------------------------------------------------------------*
FORM process_invoice USING iv_bkpf TYPE bkpf.
DATA: ls_bseg TYPE bseg,
ls_lfa1 TYPE lfa1,
ld_due_date TYPE d.
DATA: ls_event TYPE ty_event_log.
" Get Vendor and other details from first line item
SELECT SINGLE * FROM bseg INTO ls_bseg
WHERE bukrs = iv_bkpf-bukrs
AND belnr = iv_bkpf-belnr
AND gjahr = iv_bkpf-gjahr
AND koart = 'K'.
IF sy-subrc = 0.
SELECT SINGLE name1 FROM lfa1 INTO ls_lfa1-name1 WHERE lifnr = ls_bseg-lifnr.
CALL FUNCTION 'DETERMINE_DUE_DATE'
EXPORTING
i_zfbdt = ls_bseg-zfbdt
i_zbd1t = ls_bseg-zbd1t
i_zbd2t = ls_bseg-zbd2t
i_zbd3t = ls_bseg-zbd3t
i_zbd1p = ls_bseg-zbd1p
i_zbd2p = ls_bseg-zbd2p
i_zterm = ls_bseg-zterm
IMPORTING
e_faedt = ld_due_date.
ENDIF.
" Helper function to populate common fields
MACRO set_common_fields.
ls_event-invoice = iv_bkpf-belnr.
ls_event-sourcesystem = gv_system_id.
ls_event-lastdataupdate = gv_last_update.
ls_event-companycode = iv_bkpf-bukrs.
ls_event-vendorname = ls_lfa1-name1.
ls_event-invoiceduedate = ld_due_date.
SELECT SINGLE wrbtr FROM bseg INTO ls_event-invoiceamount WHERE belnr = iv_bkpf-belnr AND gjahr = iv_bkpf-gjahr AND koart = 'K'.
ENDMACRO.
" 1. Invoice Received
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Invoice Received'.
CONCATENATE iv_bkpf-cpudt iv_bkpf-cputm INTO ls_event-eventtime.
ls_event-username = iv_bkpf-usnam.
APPEND ls_event TO gt_event_log.
" 2. Invoice Parked (if document was created as parked)
IF iv_bkpf-bstat = 'V'.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Invoice Parked'.
CONCATENATE iv_bkpf-cpudt iv_bkpf-cputm INTO ls_event-eventtime.
ls_event-username = iv_bkpf-usnam.
APPEND ls_event TO gt_event_log.
ENDIF.
" 10. Invoice Posted (For non-parked, same as received. For parked, this needs CDHDR/CDPOS logic not shown for brevity)
IF iv_bkpf-bstat <> 'V'.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Invoice Posted'.
CONCATENATE iv_bkpf-budat iv_bkpf-cputm INTO ls_event-eventtime. " Using posting date
ls_event-username = iv_bkpf-usnam.
APPEND ls_event TO gt_event_log.
ENDIF.
" 5. & 7. Invoice Blocked / Discrepancy Resolved from Change Docs
DATA: lt_cdhdr TYPE TABLE OF cdhdr, lt_cdpos TYPE TABLE OF cdpos.
DATA(ld_objectkey) = |{ iv_bkpf-bukrs }{ iv_bkpf-belnr }{ iv_bkpf-gjahr }|.
SELECT * FROM cdhdr INTO TABLE lt_cdhdr WHERE objectclas = 'BELEG' AND objectid = ld_objectkey.
IF sy-subrc = 0.
SELECT * FROM cdpos INTO TABLE lt_cdpos FOR ALL ENTRIES IN lt_cdhdr
WHERE changenr = lt_cdhdr-changenr AND tabname = 'BSEG' AND fname = 'ZLSPR'.
LOOP AT lt_cdpos ASSIGNING FIELD-SYMBOL(<fs_cdpos>).
READ TABLE lt_cdhdr ASSIGNING FIELD-SYMBOL(<fs_cdhdr>) WITH KEY changenr = <fs_cdpos>-changenr.
IF sy-subrc = 0.
CLEAR ls_event.
set_common_fields.
IF <fs_cdpos>-value_new IS NOT INITIAL AND <fs_cdpos>-value_old IS INITIAL.
ls_event-activityname = 'Invoice Blocked For Payment'.
ELSEIF <fs_cdpos>-value_new IS INITIAL AND <fs_cdpos>-value_old IS NOT INITIAL.
ls_event-activityname = 'Discrepancy Resolved'.
ELSE.
CONTINUE.
ENDIF.
CONCATENATE <fs_cdhdr>-udate <fs_cdhdr>-utime INTO ls_event-eventtime.
ls_event-username = <fs_cdhdr>-username.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDIF.
" 6. 8. 9. Workflow Events (Routed, Approved, Rejected) - Simplified Example
" This requires knowledge of specific workflow templates. Placeholder logic:
" SELECT ... FROM SWW_WI2OBJ ... WHERE INSTID = [Invoice Object]
" SELECT ... FROM SWWWIHEAD ... to get status and times
" 11. & 12. & 14. Payment Proposal, Executed, Cleared
IF ls_bseg-augbl IS NOT INITIAL.
DATA: ls_regup TYPE regup.
SELECT SINGLE * FROM regup INTO ls_regup WHERE vblnr = ls_bseg-belnr.
IF sy-subrc = 0.
DATA(ld_rundate) = ls_regup-laufd.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Payment Proposal Created'.
CONCATENATE ld_rundate '000000' INTO ls_event-eventtime.
APPEND ls_event TO gt_event_log.
ENDIF.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Payment Executed'.
CONCATENATE ls_bseg-augdt '120000' INTO ls_event-eventtime. " Using clearing date as proxy
APPEND ls_event TO gt_event_log.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Payment Cleared'.
CONCATENATE ls_bseg-augdt '120001' INTO ls_event-eventtime.
APPEND ls_event TO gt_event_log.
ENDIF.
" 13. Invoice Due Date Passed (Calculated)
IF ls_bseg-augdt IS NOT INITIAL AND ld_due_date IS NOT INITIAL.
IF ls_bseg-augdt > ld_due_date.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Invoice Due Date Passed'.
CONCATENATE ld_due_date '235959' INTO ls_event-eventtime.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDIF.
" 15. Invoice Cancelled
IF iv_bkpf-stblg IS NOT INITIAL.
DATA: ls_rev_bkpf TYPE bkpf.
SELECT SINGLE * FROM bkpf INTO ls_rev_bkpf WHERE belnr = iv_bkpf-stblg.
IF sy-subrc = 0.
CLEAR ls_event.
set_common_fields.
ls_event-activityname = 'Invoice Cancelled'.
CONCATENATE ls_rev_bkpf-cpudt ls_rev_bkpf-cputm INTO ls_event-eventtime.
ls_event-username = ls_rev_bkpf-usnam.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form PROCESS_MM_INVOICE (Handles MM/Logistics Invoices)
*&---------------------------------------------------------------------*
FORM process_mm_invoice USING iv_rbkp TYPE rbkp.
" This form would be similar to PROCESS_INVOICE, but starts with RBKP.
" It needs to find the corresponding FI document in BKPF via AWKEY.
" The logic for PO/GR Matched would be included here.
" For demonstration, creating placeholder events for MM-specific activities.
DATA: ls_event TYPE ty_event_log.
ls_event-invoice = iv_rbkp-belnr.
ls_event-sourcesystem = gv_system_id.
ls_event-lastdataupdate = gv_last_update.
ls_event-companycode = iv_rbkp-bukrs.
" 1. Invoice Received (MM)
ls_event-activityname = 'Invoice Received'.
CONCATENATE iv_rbkp-cpudt iv_rbkp-cputm INTO ls_event-eventtime.
ls_event-username = iv_rbkp-usnam.
APPEND ls_event TO gt_event_log.
" 3. Purchase Order Matched (Implicit)
ls_event-activityname = 'Purchase Order Matched'.
CONCATENATE iv_rbkp-cpudt iv_rbkp-cputm INTO ls_event-eventtime.
ls_event-username = iv_rbkp-usnam.
APPEND ls_event TO gt_event_log.
" 4. Goods Receipt Matched (Implicit)
ls_event-activityname = 'Goods Receipt Matched'.
CONCATENATE iv_rbkp-cpudt iv_rbkp-cputm INTO ls_event-eventtime.
ls_event-username = iv_rbkp-usnam.
APPEND ls_event TO gt_event_log.
" NOTE: The rest of the events (Block, Pay, etc.) would be found by linking
" RBKP to BKPF and then reusing the logic from PROCESS_INVOICE.
" Link: BKPF-AWKEY = CONCATENATE( RBKP-BELNR, RBKP-GJAHR ).
ENDFORM.
*&---------------------------------------------------------------------*
*& Form WRITE_OUTPUT_FILE
*&---------------------------------------------------------------------*
FORM write_output_file.
DATA: lv_string TYPE string.
OPEN DATASET p_fpath FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
IF sy-subrc <> 0.
MESSAGE 'Error opening file.' TYPE 'E'.
RETURN.
ENDIF.
" Write Header
lv_string = 'Invoice,ActivityName,EventTime,SourceSystem,LastDataUpdate,UserName,CompanyCode,VendorName,InvoiceAmount,PurchaseOrderNumber,InvoiceDueDate'.
TRANSFER lv_string TO p_fpath.
" Write Data
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_event>).
" Create a comma-separated string, handling potential commas in data
CONCATENATE <fs_event>-invoice
<fs_event>-activityname
<fs_event>-eventtime
<fs_event>-sourcesystem
<fs_event>-lastdataupdate
<fs_event>-username
<fs_event>-companycode
<fs_event>-vendorname
<fs_event>-invoiceamount
<fs_event>-purchaseordernumber
<fs_event>-invoiceduedate
INTO lv_string SEPARATED BY ','.
TRANSFER lv_string TO p_fpath.
ENDLOOP.
CLOSE DATASET p_fpath.
WRITE: / 'Extraction complete. File written to:', p_fpath.
ENDFORM.
`