应付账款发票处理数据模板
应付账款发票处理数据模板
- 全面分析所需的推荐属性
- 有效跟踪流程的关键活动
- 分步数据提取指南
应付账款发票处理属性
| 名称 | 说明 | ||
|---|---|---|---|
| 事件时间 EventTime | 活动发生的准确日期和时间。 | ||
| 说明 事件时间是与每项活动关联的时间戳,用于确定发票事件的先后顺序。这些数据对于了解流程顺序和开展各类时间分析至关重要。 在分析中,事件时间用于正确排列活动、计算不同步骤之间的周期时间、识别等待时间,以及分析不同时段(如逐月)的流程绩效。它是所有基于时长的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 | 发票凭证的唯一标识符,也是应付账款流程的主要案例ID。 | ||
| 说明 发票是连接从接收到付款所有相关活动的核心对象。在SAP S/4HANA中,发票通常由公司代码(BUKRS)、唯一凭证编号(BELNR)和会计年度(GJAHR)组成复合键。 按发票分析可以完整了解发票的端到端生命周期。这是计算总周期时间、识别单张发票的瓶颈,以及了解发票在流程中可能经历的不同路径的基础。 重要性 此标识符可唯一标记每张发票的处理过程,从而追踪完整生命周期,并逐个案例分析流程绩效。 获取途径 此复合键取自BKPF(会计凭证抬头)或RBKP(发票收据凭证抬头)表中的BUKRS、BELNR和GJAHR字段。 示例 1000-1900000001-20231710-1900000002-20232000-5100000003-2024 | |||
| 活动 ActivityName | 发票处理生命周期中发生的具体业务事件或步骤的名称。 | ||
| 说明 活动表示应付账款流程中的一个独立阶段或操作,例如“收到发票”“发票已过账”或“已执行付款”。这些活动构成流程图的基本要素。 活动分析是流程挖掘的核心。它有助于呈现流程顺序、识别常见路径、发现偏离标准流程的情况,并衡量每个步骤的频次和持续时间。特定发票的活动顺序构成其流程路径。 重要性 活动定义了流程步骤,可用于呈现和分析流程顺序、识别瓶颈并发现返工环节。 获取途径 数据可来自多个来源,包括凭证状态变更(如BKPF-BSTAT)、更改凭证(CDHDR/CDPOS表)或工作流日志。通常需要自定义提取逻辑。 示例 收到发票发票已批准已执行付款发票因付款被阻止 | |||
| 上次数据更新时间 LastDataUpdate | 表示此记录的数据上次从源系统刷新时间的时间戳。 | ||
| 说明 此属性记录最近一次从SAP S/4HANA提取或更新数据的日期和时间。它是元数据字段,对于了解所分析数据的新鲜度至关重要。 用户可据此了解流程分析所用数据的时效性,从而合理预期数据延迟,并安排数据刷新、维护数据完整性。 重要性 显示数据的新鲜度,让用户了解流程分析所依据的数据是否为最新。 获取途径 此值在从源系统提取数据时生成,并写入每条记录。 示例 2024-05-20T04:00:00Z2024-05-21T04:00:00Z | |||
| 源系统 SourceSystem | 提取数据的系统。 | ||
| 说明 此属性标识流程数据的来源。对于此视图,该值通常为“SAP S/4HANA”。 在包含多个ERP或集成系统的环境中,此字段对于数据沿袭和隔离至关重要。它可确保分析使用正确的数据集,并帮助追溯数据质量问题的来源。 重要性 标识数据来源,对于数据治理、故障排查和多系统环境至关重要。 获取途径 通常在数据提取过程中添加一个固定值,用于标记数据集的来源。 示例 SAP S/4HANASAP ECC 6.0S4H_PROD_100 | |||
| 供应商名称 VendorName | 提交发票的供应商名称。 | ||
| 说明 此属性包含供应商的正式名称,通过发票凭证中的供应商编号关联。 供应商分析对于管理供应商关系和发现特定供应商相关的流程问题至关重要。例如,可以分析“哪些供应商提交的发票差异最多?”或“我们是否始终按时向某些战略供应商付款?”。此外,供应商名称与发票编号和金额结合使用,也是识别潜在重复付款的重要字段。 重要性 支持按供应商分析流程绩效,帮助识别存在问题的供应商并有效管理战略供应商关系。 获取途径 通过BKPF或RBKP中的供应商编号(LIFNR)关联供应商主数据表LFA1,并读取NAME1字段。 示例 办公用品公司环球咨询集团Machine Parts GmbH | |||
| 公司代码 CompanyCode | 处理发票的组织单位。 | ||
| 说明 公司代码是能够编制完整、独立对外报告账目的最小组织单位。在应付账款场景中,它代表欠供应商款项的法律实体。 按公司代码分析,可以比较组织内不同法律实体的流程绩效,帮助识别哪些业务部门遵循标准流程,哪些部门效率较低、周期时间较长或返工率较高。 重要性 支持比较不同法律实体的流程绩效,帮助发现区域或业务单元特有的问题和最佳实践。 获取途径 位于凭证抬头表中,FI发票主要使用BKPF-BUKRS,MM发票使用RBKP-BUKRS。 示例 10001710US01DE01 | |||
| 发票到期日 InvoiceDueDate | 应向供应商支付发票款项的截止日期。 | ||
| 说明 发票到期日是向供应商付款的截止日期。按时付款有助于避免逾期费用并维护良好的供应商关系。此日期根据发票基准日期和与供应商约定的付款条件计算。 此日期对于“Payment Compliance & Aging”仪表板和“On-Time Payment Rate”KPI至关重要。将到期日与实际付款日期进行比较,可以判断付款是否按时、提前或延迟,并了解其对财务和供应商关系的直接影响。 重要性 这是按时付款分析的主要依据,可用于衡量付款绩效及其对供应商关系和逾期费用的影响。 获取途径 此日期通常通过计算得出。净到期日位于BSEG-NETDT字段,也可根据付款基准日期(BSEG-ZFBDT)和付款条件(BSEG-ZTERM)推算。 示例 2023-10-312023-11-152024-01-10 | |||
| 发票金额 InvoiceAmount | 发票原始凭证币种下的含税总金额。 | ||
| 说明 这是供应商提交的发票总金额,包括商品或服务费用、税费及其他费用,未扣除任何款项或折扣。 发票金额是多种分析所需的重要财务属性,可用于优先处理高金额发票、了解流程延误造成的财务影响(如大额发票产生的逾期费用),以及细分流程(如“高金额发票是否采用不同的审批路径?”)。它也是识别潜在重复付款的必要依据。 重要性 为流程分析提供财务背景,支持按金额分析、优先处理高金额发票并量化财务影响。 获取途径 MM发票的金额可从RBKP-RMWWR(发票含税总额)等表中获取;FI发票的金额可根据BSEG行项目的WRBTR字段计算。 示例 1500.00250.7512345.50 | |||
| 用户名 UserName | 执行活动人员的用户ID。 | ||
| 说明 此属性记录负责执行特定活动(如过账、审批或结清发票)的SAP用户ID,将流程步骤与具体用户关联起来。 按用户名分析有助于了解工作量分配、识别表现突出的人员,并找出可能需要额外培训的用户。它也是仪表板分析审批瓶颈的关键字段,可帮助识别导致流程延误的具体审批人。 重要性 将活动关联到具体人员,以便分析用户绩效、工作量以及是否遵守职责分离政策。 获取途径 通常可在BKPF-USNAM(录入人)等抬头表字段,或更改凭证表CDHDR-USERNAME(更改人)中找到。 示例 ABROWNJSMITHAP_AUTOMATION | |||
| 采购订单编号 PurchaseOrderNumber | 与发票关联的采购订单唯一标识符(如适用)。 | ||
| 说明 此属性将发票与预先批准的采购订单(PO)关联。PO编号是三方匹配(PO-发票-收货记录)的基础。 此属性对于合规和效率分析至关重要,可用于计算衡量采购政策执行情况的“PO-Less Invoice Percentage”KPI,也是“3-Way Matching Performance”仪表板的基础,支持分析有PO支持的发票匹配流程。 重要性 对于分析三方匹配效率和衡量采购政策执行情况至关重要,可用于识别未关联PO的发票。 获取途径 位于发票行项目表中,例如MM发票的RSEG-EBELN或FI发票的BSEG-EBELN。 示例 45000012344500005678 | |||
| 付款冻结原因 BlockingReason | 发票被冻结付款的原因,通常表示存在差异。 | ||
| 说明 发票在三方匹配或其他核验环节未通过检查时,会被冻结付款。付款冻结原因用于说明问题性质,例如数量差异、价格差异或缺少收货记录。 此属性对“发票差异返工分析”仪表板至关重要。分析各类冻结原因的出现频率,有助于找出流程低效的根本原因。例如,如果“价格差异”很常见,可能说明采购系统中的主数据存在问题。 重要性 直接揭示发票差异和返工的根本原因,帮助您有针对性地改进流程。 获取途径 存储在RSEG等发票行项目表中,字段通常以SPGR*开头(如SPGRP、SPGRQ、SPGRT),也可在RBKP_BLOCKED中找到。 示例 价格差异数量差异缺少收货记录 | |||
| 付款条件 PaymentTerms | 与供应商约定的发票付款条件,通常包括折扣机会。 | ||
| 说明 付款条件规定了付款到期日和提前付款折扣等规则。例如,条件“Z001”可能表示“30天内付款,10天内付款可享受2%的折扣”。 此属性是“提前付款折扣获取率”仪表板的基础。分析付款条件后,可以找出所有符合折扣条件的发票。将这些发票与实际享受折扣的发票进行比较,即可发现错失的节省机会,并衡量付款流程的效率。 重要性 对于分析提前付款折扣机会、衡量付款流程的财务表现以及发现错失的节省机会,这一属性至关重要。 获取途径 可在供应商行项目表BSEG-ZTERM或发票抬头表RBKP-ZTERM中找到。 示例 Z0010001NT30 | |||
| 供应商发票编号 VendorInvoiceNumber | 供应商在发票凭证上提供的发票编号。 | ||
| 说明 这是供应商自身会计系统中的参考编号,印在纸质或电子发票上。接收发票时,工作人员会手动录入该编号,或通过OCR识别获取。 此字段对日常运营和分析都非常重要,尤其适用于“潜在重复发票付款”仪表板。检测重复发票的一种常见方法,是查找供应商名称、供应商发票编号和发票金额均相同的多张内部发票。它是发票最主要的外部参考编号。 重要性 这是识别潜在重复付款的关键字段,也是与供应商沟通时最主要的外部参考编号。 获取途径 存储在凭证抬头的“参考”字段中,通常为BKPF-XBLNR。 示例 INV-2023-9876733401120231015-001 | |||
| 发票凭证类型 InvoiceDocumentType | 发票凭证的分类,决定其在SAP中的处理方式。 | ||
| 说明 凭证类型是SAP中的关键配置项,用于对会计凭证分类。例如,KR通常用于供应商发票,RE用于MM发票,KG用于供应商贷项通知单。凭证类型决定编号范围和必填字段等设置。 在流程分析中,按凭证类型筛选可以比较不同发票类型的流程路径。例如,贷项通知单的审批流程可能与标准发票不同。这对于“Invoice Approval Routing Variants”仪表板很有帮助。 重要性 支持按发票类型细分流程,揭示不同处理路径和周期时间的差异。 获取途径 直接取自凭证抬头表的BKPF-BLART字段。 示例 KRREKG | |||
| 发票币种 InvoiceCurrency | 发票金额所用的币种代码(如USD、EUR)。 | ||
| 说明 此属性指定发票金额所用的币种,为所有财务数值提供必要背景信息。 对于跨国组织,如果不考虑币种就分析发票,结果可能产生误导。此字段支持正确处理财务数据,您可以将所有金额换算为统一的报告币种,也可以按币种划分数据,了解各地区的财务活动。 重要性 为发票金额提供必要背景信息,支持准确的财务分析和报告,尤其适用于跨国业务。 获取途径 可在凭证抬头表中找到,主要字段为BKPF-WAERS或RBKP-WAERS。 示例 USDEURGBPJPY | |||
| 已享受折扣 DiscountTaken | 用于标记是否成功享受了提前付款折扣的布尔值。 | ||
| 说明 此属性表示发票付款时是否实际享受了现金折扣,是衡量应付账款流程财务效率的重要组成部分。 此标记是“提前付款折扣获取率”KPI的核心。先根据付款条件筛选符合折扣条件的发票,再分析此标记,企业便可准确计算节省的金额和错失的节省机会。这为应付账款表现提供了清晰、可量化的衡量依据。 重要性 直接衡量企业成功获取可用提前付款折扣的情况,而这会直接影响公司的利润。 获取途径 检查付款凭证中的折扣金额字段BSEG-SKNTO是否大于零,即可得出此值。 示例 truefalse | |||
| 是否自动执行 IsAutomated | 用于标记活动是由系统自动执行,还是由人工用户执行。 | ||
| 说明 此布尔属性用于区分人工发起的活动与系统作业、工作流或机器人执行的活动。例如,自动付款运行或系统生成的发票过账会标记为自动执行。 分析此属性有助于了解应付账款流程的自动化程度,可用于衡量自动化项目的成效、比较自动步骤与人工步骤的效率,并发现进一步自动化的机会。 重要性 帮助衡量流程的自动化程度,分析自动化效果并发现进一步改进的机会。 获取途径 根据用户名(如SAP_SYSTEM或BATCHUSER等系统用户ID)或与自动化作业关联的特定事务代码推断。 示例 truefalse | |||
| 是否逾期付款 IsLatePayment | 用于标记发票是否在到期日之后付款的布尔值。 | ||
| 说明 此计算属性是一个简单的真/假标记,用于表示发票是否在正式到期日之后付款。系统通过比较“清账日期”和“发票到期日”得出该值。 此标记简化了“付款合规与账龄”仪表板和“按时付款率”KPI的分析。您可以轻松筛选和汇总数据,统计逾期付款数量、计算按时付款比例,并找出逾期付款率较高的供应商或公司代码。 重要性 直接衡量付款是否符合约定条件,简化按时付款KPI的计算,并帮助发现付款表现不佳的环节。 获取途径 计算属性。逻辑为:IF ClearingDate > InvoiceDueDate THEN true ELSE false。 示例 truefalse | |||
| 清账日期 ClearingDate | 付款完成且发票从未清项目中清账的日期。 | ||
| 说明 清账日期表示发票已完成财务结算。该日期对应“付款已清账”活动,通常标志着发票成功处理流程的最后一步。 此日期用于计算实际付款日期,并与发票到期日进行比较。因此,它是计算“按时付款率”KPI和分析付款表现的关键数据,也用于确定端到端发票周期时间的终点。 重要性 标志着发票最终结算,可作为周期时间计算的终点,也是分析按时付款情况的依据。 获取途径 可在已清账项目表中找到,例如供应商项目表BSAK-AUGDT。 示例 2023-10-282023-11-142024-01-09 | |||
应付账款发票处理活动
| 活动 | 说明 | ||
|---|---|---|---|
| 付款已结清 | 此活动标志着发票最终结清,付款与发票在明细分类账中完成核销,流程至此结束。 | ||
| 重要性 作为流程的最终节点,此活动对于准确计算端到端周期时间至关重要,并确认负债已结清。 获取途径 当发票凭证供应商行项目(表BSEG)中的结清日期(AUGDT)字段有值时,即明确记录此事件。 采集 使用发票行项目中的结清日期(BSEG-AUGDT)。 事件类型 explicit | |||
| 发票因付款被阻止 | 系统自动或人工为发票设置了付款冻结,因此无法付款。通常是由于价格或数量不符,或缺少审批。 | ||
| 重要性 这是问题和返工的重要指标。分析冻结原因和持续时间,有助于找出付款延误和流程低效的根本原因。 获取途径 此状态明确记录在会计凭证供应商行项目的付款冻结码字段(ZLSPR)中(表BSEG)。 采集 当BSEG-ZLSPR字段填入冻结原因时,系统会通过更改凭证记录此事件。 事件类型 explicit | |||
| 发票已取消 | 发票凭证已冲销,其财务影响随之抵消。这是流程的另一种结束状态,通常由录入错误或供应商争议导致。 | ||
| 重要性 跟踪取消情况有助于发现流程失败的原因,例如重复提交或发票数据错误,并据此排查上游问题。 获取途径 创建冲销凭证时会明确记录此事件。原始凭证抬头(BKPF)中会填写冲销凭证编号(STBLG)和冲销原因。 采集 查找冲销凭证的过账日期,该凭证编号记录在原始凭证抬头(BKPF-STBLG)中。 事件类型 explicit | |||
| 发票已批准 | 发票已在工作流系统中获得所有必要审批。这通常是发票过账或解除付款冻结前的最后一步。 | ||
| 重要性 这一关键里程碑标志着审批周期结束。从提交审批到获批所需的时间是衡量效率的重要指标。 获取途径 从SAP Business Workflow日志中获取完成或最终放行步骤。也可以根据提交审批后付款冻结被移除这一情况推断。 采集 从SAP工作流日志中提取工作流完成事件,或识别最终的“放行”事件。 事件类型 explicit | |||
| 发票已过账 | 发票正式记入总账,形成财务负债。暂存凭证可以转为已过账凭证,也可以直接过账。 | ||
| 重要性 这是重要的财务里程碑,确认公司有付款义务,通常也是安排付款的前提。 获取途径 根据凭证抬头(BKPF)中的过账日期(BUDAT)识别此事件。已过账凭证的凭证状态(BKPF-BSTAT)为空白。 采集 对于未暂存的凭证(BKPF-BSTAT为空白),使用过账时间戳(BKPF-BUDAT)。 事件类型 explicit | |||
| 已执行付款 | 发票款项已支付。付款运行完成并创建、过账付款凭证时会记录此事件。 | ||
| 重要性 此活动对于现金流分析和衡量“On-Time Payment Rate”KPI至关重要,可将此日期与发票到期日进行比较。 获取途径 根据结清发票的付款凭证过账日期获取此事件。付款凭证编号记录在发票行项目(BSEG)的结清凭证字段(AUGBL)中。 采集 查找结清发票行项目的付款凭证过账日期(BUDAT)。 事件类型 explicit | |||
| 收到发票 | 此活动表示SAP中创建了发票凭证,可以由人工创建,也可以通过OCR/VIM等自动化接口创建。通常根据会计凭证抬头的创建日期和时间记录此事件。 | ||
| 重要性 作为流程的起点,此活动对于计算发票端到端周期时间和衡量整个应付账款流程的处理量至关重要。 获取途径 此事件取自会计凭证抬头表BKPF,使用凭证创建日期(CPUDT)和时间(CPUTM)。 采集 使用发票凭证的创建时间戳(BKPF-CPUDT、BKPF-CPUTM)。 事件类型 explicit | |||
| 发票已拒绝 | 审批人在审批工作流中拒绝了发票。通常,系统会将发票退回给处理人员,以便更正或补充说明。 | ||
| 重要性 跟踪拒绝情况有助于发现审批流程中的返工环节,也可能揭示政策执行或发票编码方面的问题。 获取途径 此事件作为特定结果记录在与发票关联的SAP Business Workflow日志中。 采集 从SAP工作流日志中提取工作流“已拒绝”状态事件。 事件类型 explicit | |||
| 发票已提交审批 | 发票已根据业务规则提交至工作流,等待必要审批。这标志着审批子流程开始。 | ||
| 重要性 此活动是衡量“Average Invoice Approval Time”KPI和分析审批瓶颈的起点。 获取途径 可从SAP Business Workflow日志(SWW*表)中获取,这些日志记录与发票对象(如BUS2081)关联的工作流实例启动时间。 采集 从与发票凭证关联的SAP工作流日志(如表SWW_WIHEAD)中提取工作流启动事件。 事件类型 explicit | |||
| 发票已过到期日 | 此计算事件表示发票净到期日已过,但尚无付款结清记录,说明付款已逾期或延迟。 | ||
| 重要性 此活动对于“Payment Compliance & Aging”仪表板至关重要,有助于主动发现和管理逾期发票,并分析付款延迟的根本原因。 获取途径 SAP中没有明确记录此事件。系统通过将当前日期与净到期日进行比较来计算,净到期日根据BSEG-ZFBDT或基准日期及付款条件得出。 采集 当事件时间戳晚于发票净到期日时触发的计算事件。 事件类型 calculated | |||
| 差异已解决 | 此活动表示先前发现的问题(可能导致付款冻结)已调查并解决。移除发票付款冻结时会记录此事件。 | ||
| 重要性 跟踪这一返工环节对于“Invoice Discrepancy Rework Analysis”仪表板至关重要,有助于量化纠错所花费的时间和精力。 获取途径 根据显示付款冻结已移除的更改凭证推断此事件。BSEG-ZLSPR字段的更改日志是主要数据来源。 采集 查找表BSEG的更改凭证,其中ZLSPR字段从某个值变为空白。 事件类型 inferred | |||
| 已创建付款建议 | 发票已纳入付款运行(如F110)的付款建议中。待付款运行最终执行后,即可安排付款。 | ||
| 重要性 此活动显示未结负债转为正在准备付款的项目,有助于分析付款运营效率。 获取途径 此事件明确记录在付款运行数据表中,具体包括REGUP(付款程序处理项目)和REGUH(抬头)。 采集 查找发票出现在表REGUP中的时间,并关联REGUH中标识的付款运行。 事件类型 explicit | |||
| 已匹配收货记录 | 此活动表示发票数量和金额已成功匹配到相应的收货凭证。这是三方匹配场景中的最终验证步骤。 | ||
| 重要性 跟踪此活动有助于找出三方匹配流程中的低效环节,并发现实际收货与供应商开票内容之间的差异。 获取途径 如果发票行项目中存在物料凭证(收货)引用,通常可通过采购订单项目历史记录关联,即可推断此事件。 采集 如果发票行项目中存在收货凭证引用,即可推断此事件,例如MIRO发票的RSEG表中。 事件类型 inferred | |||
| 已匹配采购订单 | 此活动表示发票已成功匹配到相应的采购订单。这是采购类发票三方匹配流程中的关键步骤。 | ||
| 重要性 分析此活动有助于衡量匹配流程的效率,也是“3-Way Matching Performance”和“PO-Less Invoice Percentage”KPI的基础。 获取途径 当表BSEG或ACDOCA中的发票行项目包含有效的采购订单号(EBELN)和项目号(EBELP)时,可推断此事件。 采集 发票凭证创建时,如果存在采购订单引用(BSEG-EBELN),即可推断此事件。 事件类型 inferred | |||
| 暂存发票 | 表示发票已录入系统,但尚未过账到总账。通常这是有意为之,以便先保存未完成的凭证,稍后再处理或审批。 | ||
| 重要性 跟踪暂存发票有助于发现正式过账前的延误,也能揭示数据不完整或初步验证方面的问题。 获取途径 根据会计凭证抬头中的凭证状态字段推断此状态(BKPF-BSTAT = 'V'表示暂存)。状态设置时即发生此事件。 采集 查找表BKPF的更改凭证,其中BSTAT字段设为'V'(Vor-erfasst/预录入)。 事件类型 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)和相关公司代码。
- 准备主查询:将查询部分提供的完整SQL查询复制到SQL客户端。该查询使用公用表表达式(CTE)先选出发票基础数据,再整合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架构的SELECT权限。仅具备SAP GUI中的应用级访问权限并不足够。
- 性能注意事项:直接查询I_ChangeDocument可能消耗大量资源。提供的查询会先筛选发票,以降低这一影响。对于超大型数据集,可考虑在非高峰时段运行提取,或按较短日期范围分批执行。
查询示例 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表的SAP HANA架构。获取连接字符串、凭据、架构名称,以及读取BKPF、ACDOCA和其他相关表所需的权限。这些表可能用于存储暂存凭证、工作流、采购、收货、付款建议、清账和冲销数据。
- 执行前确认目标系统的技术数据模型。核实系统使用的物理名称、关键字段、时间戳字段、冲销关系、付款关系和工作流持久化方式。将查询中每个方括号占位符替换为系统中对应的对象或字段。不要假设工作流或暂存凭证数据都存储在某个通用表中。
- 配置提取参数。设置[Start date]、[End date]、[Company code filter]、[Document type filter]和[Schema name]。初次提取建议使用三至六个月的日期范围,确认性能和数据完整性后再扩大范围。
- 在经批准的SAP HANA SQL客户端中执行SQL查询,例如SAP HANA Database Explorer或其他获授权的SQL执行工具。查询会为每项明确提取的活动输出一行,不会依赖ProcessMind推断事件。
- 验证结果集。确认Invoice为案例标识符,ActivityName包含全部15个所需活动名称,EventTime已填充且时间顺序合理,SourceSystem标识SAP S/4HANA,LastDataUpdate包含提取刷新时间戳。加载数据前,请检查重复事件、冲销关系和凭证关联。
- 应用系统所需的映射。例如,将配置的暂存凭证来源映射为Invoice Parked,将配置的工作流来源映射为Invoice Routed For Approval、Invoice Approved和Invoice Rejected,并将配置的付款来源映射为Payment Proposal Created和Payment Executed。如需完整审计,请在其他列中保留源标识符。
- 将结果导出为分隔符文件或数据库结果集,每行对应一个事件。使用UTF-8编码,统一时间戳时区,并保留以下准确列名:Invoice、ActivityName、EventTime、SourceSystem、LastDataUpdate、UserName、CompanyCode、VendorName、InvoiceAmount、PurchaseOrderNumber和InvoiceDueDate。不要按发票汇总活动。
- 将事件日志上传到ProcessMind,并将Invoice设为案例标识符、ActivityName设为活动列、EventTime设为事件时间列。确认可选属性已映射到相应字段。ProcessMind会按原样读取事件日志,因此上传前请确保所有需要可视化的活动都已作为数据行包含在内。
配置
- **日期范围:**从三至六个月开始。根据提取的活动,使用过账日期、凭证创建日期或相关源事件日期。确认查询运行时间和源数据保留情况后,再扩大范围。
- **公司筛选:**设置[Company code filter],将提取范围限制为所需公司代码。如果无需限制,请使用受控的全公司选择,而不要在生产环境中运行不受限制的查询。
- **凭证筛选:**确认目标系统中供应商发票、贷项通知单、暂存凭证、付款凭证和冲销所用的凭证类型后,再设置[Document type filter]。
- **架构与对象映射:**将[Schema name]及所有方括号中的源对象或字段替换为已在目标SAP S/4HANA系统中核实的值。直接查询HANA时,必须根据系统已激活的应用、扩展、工作流设计和数据模型进行调整。
- **时间戳处理:**将所有源时间戳统一到同一时区。如果数据只有日期,请采用有文档记录的默认时间,并在数据字典中注明这一限制。
- **事件定义:**每项活动单独提取为一行。不要将多项活动合并到一条发票记录中,也不要指望ProcessMind推导匹配、审批、到期日或清账事件。
- **到期日事件:**只有当发票到期日早于设定的评估时间戳,且截至该时间戳尚无清账事件时,才生成Invoice Due Date Passed。查询使用[Evaluation timestamp]进行计算。
- **性能:**限制初始日期范围和公司范围,筛选已索引或与分区相关的字段,避免不必要的宽字段查询,并在获批的报表时段执行。如果生产查询超出约定运行时间,可考虑先暂存部分源数据。
- **刷新策略:**将LastDataUpdate设为提取执行时间戳。增量加载时,根据相关源变更时间戳保留水位线,并设置回溯时间段,以捕获延迟更新和冲销。
- **准备条件:**所需数据库权限、经批准的生产环境访问权限、对系统通用日记账配置的了解、对已配置的暂存凭证、采购、收货、工作流、付款、清账和冲销数据源的访问权限,以及适用的SAP许可或治理审批。
查询示例 sql
WITH
params AS (
SELECT
TO_DATE('[Start date]') AS start_date,
TO_DATE('[End date]') AS end_date,
TO_TIMESTAMP('[Evaluation timestamp]') AS evaluation_ts,
TO_TIMESTAMP('[Extraction timestamp]') AS extraction_ts
FROM DUMMY
),
base_invoice AS (
SELECT
b.mandt,
b.bukrs,
b.belnr,
b.gjahr,
b.bldat,
b.budat,
b.cpudt,
b.cputm,
b.usnam,
b.blart,
b.xblnr,
b.stblg,
b.stjah,
a.lifnr,
a.wrbtr,
a.waers,
a.zfbdt,
a.zbd1t,
a.zbd2t,
a.zbd3t,
a.ebeln,
a.ebelp,
a.augbl,
a.augdt,
a.buzei,
v.name1 AS vendor_name,
CASE
WHEN a.zfbdt IS NOT NULL THEN ADD_DAYS(a.zfbdt, COALESCE(a.zbd1t, 0))
ELSE NULL
END AS invoice_due_date
FROM [Schema name].BKPF b
INNER JOIN [Schema name].ACDOCA a
ON a.mandt = b.mandt
AND a.rbukrs = b.bukrs
AND a.belnr = b.belnr
AND a.gjahr = b.gjahr
LEFT JOIN [Schema name].[Vendor master table] v
ON v.[Vendor key field] = a.lifnr
CROSS JOIN params p
WHERE b.bukrs IN ([Company code filter])
AND b.blart IN ([Document type filter])
AND b.cpudt BETWEEN p.start_date AND p.end_date
),
invoice_received AS (
SELECT DISTINCT
CAST(belnr AS NVARCHAR(40)) AS invoice,
'Invoice Received' AS activity_name,
TO_TIMESTAMP(TO_VARCHAR(cpudt, 'YYYY-MM-DD') || ' ' || COALESCE(TO_VARCHAR(cputm), '00:00:00')) AS event_time,
CAST(usnam AS NVARCHAR(80)) AS user_name,
bukrs AS company_code,
vendor_name,
wrbtr AS invoice_amount,
waers AS document_currency,
CAST(ebeln AS NVARCHAR(40)) AS purchase_order_number,
invoice_due_date
FROM base_invoice
),
invoice_parked AS (
SELECT
CAST([Parked invoice key field] AS NVARCHAR(40)) AS invoice,
'Invoice Parked' AS activity_name,
[Parked event timestamp field] AS event_time,
CAST([Parked user field] AS NVARCHAR(80)) AS user_name,
[Parked company code field] AS company_code,
[Parked vendor name field] AS vendor_name,
[Parked amount field] AS invoice_amount,
[Parked currency field] AS document_currency,
CAST([Parked purchase order field] AS NVARCHAR(40)) AS purchase_order_number,
[Parked due date field] AS invoice_due_date
FROM [Schema name].[Parked document source]
WHERE [Parked event date field] BETWEEN (SELECT start_date FROM params) AND (SELECT end_date FROM params)
AND [Parked company code field] IN ([Company code filter])
),
purchase_order_matched AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Purchase Order Matched' AS activity_name,
COALESCE([Purchase order match timestamp field], TO_TIMESTAMP(TO_VARCHAR(i.cpudt, 'YYYY-MM-DD') || ' ' || COALESCE(TO_VARCHAR(i.cputm), '00:00:00'))) AS event_time,
CAST(COALESCE([Purchase order match user field], i.usnam) AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrBtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Purchase order match source] m
ON m.[Invoice document key field] = i.belnr
AND m.[Invoice company code field] = i.bukrs
AND m.[Invoice fiscal year field] = i.gjahr
WHERE i.ebeln IS NOT NULL
),
goods_receipt_matched AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Goods Receipt Matched' AS activity_name,
[Goods receipt match timestamp field] AS event_time,
CAST(COALESCE([Goods receipt match user field], i.usnam) AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Goods receipt match source] g
ON g.[Invoice document key field] = i.belnr
AND g.[Invoice company code field] = i.bukrs
AND g.[Invoice fiscal year field] = i.gjahr
WHERE i.ebeln IS NOT NULL
),
invoice_blocked AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Invoice Blocked For Payment' AS activity_name,
[Payment block timestamp field] AS event_time,
CAST(COALESCE([Payment block user field], i.usnam) AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Payment block source] b
ON b.[Invoice document key field] = i.belnr
AND b.[Invoice company code field] = i.bukrs
AND b.[Invoice fiscal year field] = i.gjahr
WHERE [Payment block value field] IS NOT NULL
),
discrepancy_resolved AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Discrepancy Resolved' AS activity_name,
[Payment block removal timestamp field] AS event_time,
CAST(COALESCE([Payment block removal user field], i.usnam) AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Payment block history source] h
ON h.[Invoice document key field] = i.belnr
AND h.[Invoice company code field] = i.bukrs
AND h.[Invoice fiscal year field] = i.gjahr
WHERE [Previous payment block value field] IS NOT NULL
AND [New payment block value field] IS NULL
),
invoice_routed_for_approval AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Invoice Routed For Approval' AS activity_name,
[Workflow routed timestamp field] AS event_time,
CAST([Workflow initiator field] AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Workflow event source] w
ON w.[Invoice document key field] = i.belnr
AND w.[Invoice company code field] = i.bukrs
AND w.[Invoice fiscal year field] = i.gjahr
WHERE [Workflow event type field] = '[Workflow routed event value]'
),
invoice_approved AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Invoice Approved' AS activity_name,
[Workflow approval timestamp field] AS event_time,
CAST([Workflow approver field] AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Workflow event source] w
ON w.[Invoice document key field] = i.belnr
AND w.[Invoice company code field] = i.bukrs
AND w.[Invoice fiscal year field] = i.gjahr
WHERE [Workflow event type field] = '[Workflow approved event value]'
),
invoice_rejected AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Invoice Rejected' AS activity_name,
[Workflow rejection timestamp field] AS event_time,
CAST([Workflow rejector field] AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Workflow event source] w
ON w.[Invoice document key field] = i.belnr
AND w.[Invoice company code field] = i.bukrs
AND w.[Invoice fiscal year field] = i.gjahr
WHERE [Workflow event type field] = '[Workflow rejected event value]'
),
invoice_posted AS (
SELECT DISTINCT
CAST(belnr AS NVARCHAR(40)) AS invoice,
'Invoice Posted' AS activity_name,
TO_TIMESTAMP(TO_VARCHAR(budat, 'YYYY-MM-DD') || ' 00:00:00') AS event_time,
CAST(usnam AS NVARCHAR(80)) AS user_name,
bukrs AS company_code,
vendor_name,
wrbtr AS invoice_amount,
waers AS document_currency,
CAST(ebeln AS NVARCHAR(40)) AS purchase_order_number,
invoice_due_date
FROM base_invoice
WHERE stblg IS NULL
),
payment_proposal_created AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Payment Proposal Created' AS activity_name,
[Payment proposal timestamp field] AS event_time,
CAST([Payment proposal user field] AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Payment proposal source] p
ON p.[Invoice document key field] = i.belnr
AND p.[Invoice company code field] = i.bukrs
AND p.[Invoice fiscal year field] = i.gjahr
),
payment_executed AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Payment Executed' AS activity_name,
[Payment execution timestamp field] AS event_time,
CAST([Payment execution user field] AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
INNER JOIN [Schema name].[Payment execution source] p
ON p.[Invoice document key field] = i.belnr
AND p.[Invoice company code field] = i.bukrs
AND p.[Invoice fiscal year field] = i.gjahr
),
invoice_due_date_passed AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Invoice Due Date Passed' AS activity_name,
TO_TIMESTAMP(TO_VARCHAR(i.invoice_due_date, 'YYYY-MM-DD') || ' 23:59:59') AS event_time,
CAST(i.usnam AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
WHERE i.invoice_due_date IS NOT NULL
AND TO_TIMESTAMP(TO_VARCHAR(i.invoice_due_date, 'YYYY-MM-DD') || ' 23:59:59') < (SELECT evaluation_ts FROM params)
AND i.augbl IS NULL
),
payment_cleared AS (
SELECT DISTINCT
CAST(i.belnr AS NVARCHAR(40)) AS invoice,
'Payment Cleared' AS activity_name,
TO_TIMESTAMP(TO_VARCHAR(i.augdt, 'YYYY-MM-DD') || ' 00:00:00') AS event_time,
CAST(i.usnam AS NVARCHAR(80)) AS user_name,
i.bukrs AS company_code,
i.vendor_name,
i.wrbtr AS invoice_amount,
i.waers AS document_currency,
CAST(i.ebeln AS NVARCHAR(40)) AS purchase_order_number,
i.invoice_due_date
FROM base_invoice i
WHERE i.augbl IS NOT NULL
AND i.augdt IS NOT NULL
),
invoice_cancelled AS (
SELECT DISTINCT
CAST(belnr AS NVARCHAR(40)) AS invoice,
'Invoice Cancelled' AS activity_name,
TO_TIMESTAMP(TO_VARCHAR([Reversal posting date field], 'YYYY-MM-DD') || ' 00:00:00') AS event_time,
CAST(COALESCE([Reversal user field], usnam) AS NVARCHAR(80)) AS user_name,
bukrs AS company_code,
vendor_name,
wrbtr AS invoice_amount,
waers AS document_currency,
CAST(ebeln AS NVARCHAR(40)) AS purchase_order_number,
invoice_due_date
FROM base_invoice
WHERE stblg IS NOT NULL
),
all_events AS (
SELECT * FROM invoice_received
UNION ALL SELECT * FROM invoice_parked
UNION ALL SELECT * FROM purchase_order_matched
UNION ALL SELECT * FROM goods_receipt_matched
UNION ALL SELECT * FROM invoice_blocked
UNION ALL SELECT * FROM discrepancy_resolved
UNION ALL SELECT * FROM invoice_routed_for_approval
UNION ALL SELECT * FROM invoice_approved
UNION ALL SELECT * FROM invoice_rejected
UNION ALL SELECT * FROM invoice_posted
UNION ALL SELECT * FROM payment_proposal_created
UNION ALL SELECT * FROM payment_executed
UNION ALL SELECT * FROM invoice_due_date_passed
UNION ALL SELECT * FROM payment_cleared
UNION ALL SELECT * FROM invoice_cancelled
)
SELECT
invoice AS "Invoice",
activity_name AS "ActivityName",
event_time AS "EventTime",
'SAP S/4HANA' AS "SourceSystem",
(SELECT extraction_ts FROM params) AS "LastDataUpdate",
user_name AS "UserName",
company_code AS "CompanyCode",
vendor_name AS "VendorName",
invoice_amount AS "InvoiceAmount",
purchase_order_number AS "PurchaseOrderNumber",
invoice_due_date AS "InvoiceDueDate"
FROM all_events
WHERE invoice IS NOT NULL
AND event_time IS NOT NULL
ORDER BY "Invoice", "EventTime", "ActivityName"; 步骤
- 规格与设计:编码前,与业务分析师确认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等SAP源表中选取的数据。
- 选择主数据:根据用户在选择屏幕中设置的条件,从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)及工作流表的权限。此外,向应用服务器写入文件还需要授权对象S_DATASET。
查询示例 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. 减少滞纳金:立即优化应付账款发票处理
轻松降低60%的处理成本,并杜绝重复付款。
无需信用卡,几分钟即可开始。