您的“从订单到收款 - 开票与结算”数据模板
您的“从订单到收款 - 开票与结算”数据模板
- 全面分析的推荐属性
- 需跟踪的关键流程步骤和里程碑
- SAP ECC 数据提取实用指南
订单到收款 - 计费与开票属性
| 名称 | 描述 | ||
|---|---|---|---|
| 发票编号 InvoiceNumber | 计费单据的唯一标识符,作为开票流程的主要 case ID。 | ||
| 描述 发票编号(在 SAP 中称为计费凭证编号)唯一标识每张发票。在流程挖掘中,它作为 CaseId,将所有相关活动(如创建、过账、发送、付款和结清)分组为一个端到端的流程实例。 分析发票编号可以完整查看每笔计费交易从发起列到最终结算的生命周期。这对于计算应收账款周转天数 (DSO) 和整体发票周期时间等关键绩效指标至关重要,为绩效衡量和改进提供了清晰的基础。 为何重要 它是跟踪发票完整历程的核心键值,支持对每笔计费交易的周期、瓶颈和变体进行分析。 获取方式 SAP ECC 表:VBRK,字段:VBELN 示例 90001234900012359000123690001237 | |||
| 开始时间 EventTime | 指示特定活动或事件发生时间的时间戳。 | ||
| 描述 Event Time 捕获了发票生命周期中每个活动的精确日期和时间。此 timestamp 是 Process Mining 中所有基于时间的分析的基础,包括计算周期时间、识别瓶颈以及根据服务水平协议监控流程绩效。 该属性通常通过结合日期字段(如过账日期 BUDAT)和记录变更或单据创建的各种 SAP 表中的时间字段 (UZEIT) 来构建。准确的 timestamp 对于构建可靠的 event log 并确保绩效分析的有效性至关重要。 为何重要 此属性是所有绩效分析的基础,支持计算流程步骤之间的周期、持续时间和等待时间。 获取方式 由多个表中的各种日期和时间字段构建,例如 BKPF (BUDAT, CPUTM)、VBRK (ERDAT, ERZET) 以及变更日志表如 CDHDR (UDATE, UTIME)。 示例 2023-04-15T10:30:00Z2023-04-16T11:00:00Z2023-05-20T09:00:00Z | |||
| 活动 ActivityName | 发票生命周期内发生的业务事件或步骤的名称。 | ||
| 描述 此属性描述了计费流程中的特定操作或状态更改,例如“已生成发票”、“已过账发票”或“已收到客户付款”。这些活动在概念上源自各种系统事件、单据状态更改或用户执行的特定交易代码。 这些活动的顺序构成了流程流,这是流程挖掘分析的基础。通过检查这些活动,企业可以了解采取了哪些步骤、顺序如何以及频率如何,从而揭示实际流程执行与设计流程之间的差异。 为何重要 它定义了流程图中的步骤,支持流程流、偏差和瓶颈的可视化与分析。 获取方式 这是一个概念性属性,派生自多个来源,如交易代码 (CDHDR-TCODE)、单据状态更改 (VBUK-FKSTK) 和会计凭证过账。 示例 已生成发票发票已过账已发出催款单发票已清算 | |||
| 公司代码 CompanyCode | 签发发票的法律实体的标识符。 | ||
| 描述 “公司代码”代表 SAP 中一个独立的法律和会计单位。所有财务交易(包括发票)都过账到特定的公司代码。这是一个基础的组织数据元素。 在流程挖掘背景下,公司代码用于分析和比较企业内不同法律实体的计费流程绩效。这有助于识别某一实体中的最佳实践并推广到其他实体,并确保分析符合公司的组织结构。 为何重要 允许跨不同法人实体过滤和比较流程,这是财务分析和组织基准测试的基础。 获取方式 SAP ECC 表:VBRK,字段:BUKRS 示例 10002000US01DE01 | |||
| 发票总额 TotalInvoiceAmount | 计费单据的总净值。 | ||
| 描述 此属性代表发票的总净额(不含税)。发票金额是与计费流程相关的关键财务数据。 它被用于各种分析,例如将发票细分为高价值和低价值类别,以查看它们的流程流是否存在差异。它还可用于排定催收优先级,或调查为什么高价值发票需要更长的时间来获得批准或付款。这种财务背景为流程分析增加了显著的深度。 为何重要 提供必要的财务背景,支持基于发票价值进行分析,例如识别高价值发票是否遵循不同的流程或需要更长的结清时间。 获取方式 SAP ECC 表:VBRK,字段:NETWR 示例 1500.7525000.00500.0012345.67 | |||
| 客户编号 CustomerNumber | 识别发票开具对象的唯一客户编号。 | ||
| 描述 “客户编号”将发票链接到特定的客户或业务合作伙伴。此属性对于基于客户特征对计费流程进行细分和分析至关重要。 分析师可以使用此字段比较不同客户的应收账款周转天数 (DSO),识别哪些客户经常逾期,或分析付款条件合规性。理解这些模式是管理客户关系以及针对不同客户群体量身定制回款策略的关键。 为何重要 支持以客户为中心的分析,有助于识别付款行为、评估各客户的 DSO 并制定针对性的催收策略。 获取方式 SAP ECC 表:VBRK,字段:KUNRG(付款人)或 KUNAG(售达方)。 示例 100023200541CUST-A487910345 | |||
| 用户名称 UserName | 执行活动或创建单据的用户 ID。 | ||
| 描述 此属性捕获负责给定事件(如创建发票或过账付款)的 SAP 用户 ID。这对于分析流程中的人为因素至关重要。 借助这些数据,可以调查用户或团队之间的绩效差异,识别培训需求,并检测潜在的合规问题。它还用于区分人工操作与系统或批处理用户执行的自动化步骤,这是计算自动化率的关键。 为何重要 支持对用户绩效、工作负载分布的分析,并有助于区分手动和自动活动,从而支持自动化和效率提升计划。 获取方式 SAP ECC 表:VBRK,字段:ERNAM(创建者)或 BKPF,字段:USNAM(用户名)或 CDHDR,字段:USERNAME(用户)。 示例 JSMITHBW_BATCHLROSSIMKUMAR | |||
| 计费单据类型 BillingDocumentType | 用于对计费单据类型进行分类的代码,例如发票、红利通知单或借项通知单。 | ||
| 描述 “计费凭证类型”根据业务用途将交易分为不同类别。例如,“F2”是标准客户发票,而“G2”代表贷记通知单。这些分类在 SAP 中配置,用于控制不同计费凭证的处理方式。 在流程挖掘中,此属性对于过滤和比较不同计费场景至关重要。分析师可以分别检查标准发票与贷记通知单的流程,了解它们独特的流向、周期和挑战,从而实现更有针对性的流程改进。 为何重要 允许对不同的计费流程进行细分和分析(例如标准发票与红利通知单),这些流程往往具有截然不同的流程流。 获取方式 SAP ECC 表:VBRK,字段:FKART 示例 F2G2L2IV | |||
| 事务代码 TransactionCode | 用于执行活动的 SAP 交易代码。 | ||
| 描述 交易代码(简称 T-Code)是 SAP 中特定功能或程序的唯一标识符,例如用于创建计费单据的“VF01”。捕获每个事件的 T-Code 提供了流程执行情况的技术及系统级视图。 这些信息对于根本原因分析非常有价值。例如,如果错误频发,分析师可以检查是否使用了非标准的交易代码。它还有助于推导活动名称并了解流程中使用了哪些系统功能。 为何重要 提供活动执行的技术背景,支持流程偏差的根本原因分析,并有助于识别非标准的用户操作。 获取方式 SAP ECC 表:CDHDR,字段:TCODE 示例 VF01VF02FB01F-28 | |||
| 付款条款 PaymentTerms | 卖方完成销售的条件,包括付款计划。 | ||
| 描述 付款条件定义了付款到期的规则,例如“Net 30”或“Net 60”。这些条款由客户协商确定,是决定现金流的关键因素。 按付款条件分析流程可以揭示某些条款是否与较长的付款周期或较高的逾期率相关。这种见解有助于企业与客户协商更好的条款或调整其财务计划。它也是计算发票到期日的关键输入。 为何重要 帮助分析客户付款行为和协商条款对现金流的影响,为优化商业协议提供见解。 获取方式 SAP ECC 表:VBRK,字段:ZTERM 示例 Z030Z060Z001 | |||
| 最后数据更新 LastDataUpdate | 此属性指示data最后一次从Salesforce Financial Services Cloud提取的日期和时间,为分析数据“新鲜度”提供背景。这对于dashboard用户理解分析时效性至关重要,有助管理数据及时性预期,并验证data pipelines是否按计划运行。 | ||
| 描述 此属性指示数据集最后一次从源系统更新的时间。它为任何分析提供了关键背景,确保用户了解所查看数据的新鲜度。 在仪表板和报表中,此 timestamp 告知利益相关者数据的及时性,并有助于管理对近期交易可见性的预期。它通常在数据提取过程结束时生成。 为何重要 告知用户数据的及时性,这对于基于分析做出运营决策至关重要。 获取方式 在 data 提取、转换和加载 (ETL) 过程中生成并存储。 示例 2023-10-27T02:00:00Z2023-10-28T02:00:00Z | |||
| 单据日期 DocumentDate | 原始单据上的日期,由供应商或创建者提供。 | ||
| 描述 “凭证日期”是原始单据签发的日期。对于计费,这通常是发票创建的日期,常被用作计算付款截止日的基础。 该日期对财务报告和计算应收账款周转天数 (DSO) 等关键指标至关重要。从客户的角度来看,它代表了收现期的起点。分析凭证日期与过账日期之间的差异可以揭示内部处理发票的延迟。 为何重要 作为计算发票账龄和 DSO 的基准,为财务和付款条件分析提供关键参考点。 获取方式 SAP ECC 表:VBRK,字段:FKDAT(计费日期) 示例 2023-04-152023-04-162023-05-20 | |||
| 发票到期日 InvoiceDueDate | 预期的客户付款日期。 | ||
| 描述 “发票到期日”是付款条件中规定的付款截止日期。该日期是管理应收账款和启动催收活动的基础。 此属性通过与实际付款日期对比来计算“准时付款率”KPI。按到期日分析发票有助于预测现金流,并为即将到期或逾期的款项排定催收优先级。它通常由基准日期和付款条件推导得出。 为何重要 这是衡量准时付款绩效的基准,对于管理应收账款和现金流预测至关重要。 获取方式 根据基准日期 (BSEG-ZFBDT) 和付款条件 (BSEG-ZTERM) 计算得出。并不总是存储在直接字段中。 示例 2023-05-152023-05-302023-06-20 | |||
| 是否已自动化 IsAutomated | 指示活动是由系统用户执行还是通过自动化执行的标记。 | ||
| 描述 此计算属性是一个布尔标志,用于区分人工与自动化活动。它通常通过将“用户名”属性与已知系统或批处理用户 ID 列表(如“BATCHUSER”或“SAPSYSTEM”)进行对比来派生。 此标志对于衡量计费流程的自动化水平至关重要,这是许多寻求提高效率和降低成本的企业的主要目标。“自动化计费率”KPI 直接由此属性计算得出,有助于跟踪自动化计划的进展。 为何重要 直接支持自动化计费率的计算,有助于衡量流程效率并追踪自动化项目的影响。 获取方式 派生自“用户名”属性。逻辑大致为:IF UserName IN ('BATCH', 'SYSTEM', 'RFCUSER') THEN true ELSE false。 示例 truefalse | |||
| 是否返工 IsRework | 指示活动是否为返工或更正步骤的标记。 | ||
| 描述 此计算属性识别代表返工的活动,例如“发票已纠正”或单据冲销。它通常是一个布尔标志,派生自活动名称或与纠正和取消相关的交易代码,如用于取消计费单据的“VF11”。 在流程挖掘中,此标志对于量化计费流程中的返工量极具价值。它直接支持“发票纠正率”等 KPI,并帮助在流程图中可视化返工循环,从而突出增加运营成本并延迟回款的低效和质量问题。 为何重要 通过突出显示在纠正错误上花费了多少精力,帮助量化流程低效和质量问题,直接支持返工 KPI。 获取方式 派生自活动名称或事务代码。例如:IF ActivityName = 'Invoice Corrected' OR TransactionCode = 'VF11' THEN true ELSE false。 示例 truefalse | |||
| 源系统 SourceSystem | 标识数据的来源系统。 | ||
| 描述 此属性指定了数据来源的记录系统。在拥有多个 ERP 实例或集成系统的企业环境中,此字段有助于区分来自不同来源的数据。 对于流程挖掘,它对于数据校验以及跨不同系统或组织单元的流程比较分析至关重要。它通常在数据提取过程中作为静态值填充,用于标记数据集。 为何重要 提供数据来源背景,这在多系统环境中对于确保数据完整性和支持针对特定系统的分析至关重要。 获取方式 这通常是在数据提取、转换和加载 (ETL) 过程中添加的静态值,用于标识具体的 SAP ECC 实例(例如 'ECC_PROD_NA')。 示例 SAP_ECC_PRODECC_EU_100SAP_US_FIN | |||
| 结清日期 ClearingDate | 收到付款且发票从应收账款中结清的日期。 | ||
| 描述 “结清日期”是在财务系统中将未结项(如发票)标记为已付或“已结清”的日期。该日期实际上代表了现金被视为已收回并核销的时间。 这是“订单到收款”周期中最重要的日期之一。它是计算应收账款周转天数 (DSO) 和整个“发票到现金”周期的终点。分析结清日期有助于衡量催收流程的有效性。 为何重要 标志着发票生命周期的最后一步,作为 DSO 和整体周期计算的结束日期,反映回款效率。 获取方式 SAP ECC 表:BSAD,字段:AUGDT 示例 2023-05-142023-06-012023-06-25 | |||
| 货币 Currency | 发票中指定金额的货币代码。 | ||
| 描述 此属性指示交易的货币,例如 USD、EUR 或 JPY。它为所有货币值(如发票总额)提供必要的背景。 在分析跨国组织的数据时,货币字段对于正确解释和转换财务数据至关重要。它支持一致的报告,并确保金额在没有经过适当货币转换的情况下不会被加总,否则会导致错误的财务分析。 为何重要 为所有货币价值提供必要的背景,确保财务分析准确,特别是在多货币环境中。 获取方式 SAP ECC 表:VBRK,字段:WAERK 示例 美元EURGBPJPY | |||
| 过账日期 PostingDate | 凭证过账到财务会计账簿的日期。 | ||
| 描述 “过账日期”决定了交易记录在总账中的会计期间。这对于会计核算和财务报告是一个关键日期。凭证创建日期与过账日期之间的延迟可能意味着计费凭证内部处理效率低下。 从流程挖掘的角度来看,过账日期标志着发票生命周期中的一个关键里程碑。发票生成与过账之间的时间滞后可以作为衡量计费部门效率的关键绩效指标。 为何重要 标志着一个关键的财务里程碑,对会计核算至关重要。发票创建与过账之间的时间滞后是衡量内部处理效率的关键指标。 获取方式 SAP ECC 表:BKPF,字段:BUDAT 示例 2023-04-152023-04-172023-05-21 | |||
| 销售单据编号 SalesDocumentNumber | 导致发票生成的原始销售订单的标识符。 | ||
| 描述 此属性提供从发票回到发起交易的销售订单的直接链接。这种追溯能力对于完整的端到端“订单到收款”分析至关重要。 通过将计费流程与之前的销售订单流程连接,企业可以分析从客户下单到收到现金的总周期。它有助于识别计费延迟是由销售、履行还是计费部门本身的问题引起的,从而提供更全面的流程视角。 为何重要 将计费流程链接回销售订单,实现真正的端到端“订单到收款”分析,并有助于识别跨部门延迟。 获取方式 SAP ECC 表:VBRP,字段:VGBEL 示例 100000451000004610000047 | |||
| 销售组织 SalesOrganization | 负责销售产品或服务的组织单元。 | ||
| 描述 “销售组织”是 SAP 中的一个组织单元,负责分销商品和服务以及协商销售条件。它是构建销售和分销业务的关键字段。 在流程挖掘中,此属性允许从销售结构的角度分析计费流程。它支持在不同销售组织之间进行绩效比较,有助于识别哪些区域或业务线在计费流程上更高效,并支持标准化最佳实践的计划。 为何重要 支持跨不同销售部门或地区的绩效基准测试和分析,有助于识别最佳实践和改进领域。 获取方式 SAP ECC 表:VBRK,字段:VKORG 示例 1000NA01EU01AP01 | |||
订单到收款 - 计费与开票活动
| 活动 | 描述 | ||
|---|---|---|---|
| 发票已发送给客户 | 表示发票已通过定义的输出渠道(如打印、电子邮件或 EDI)发送给客户。这通常从输出管理系统日志中捕获。 | ||
| 为何重要 此事件是一个关键里程碑,它触发了客户的付款期限计时。这里的延迟直接影响预期的付款时间,并影响回款效率。 获取方式 可以从消息状态表 (NAST) 中对应发票输出类型的处理日期和时间推断出来。 捕获 从处理状态为“1”(处理成功)的 NAST 表条目中推断。 事件类型 inferred | |||
| 发票已清算 | 成功付款发票的最终状态,表示未结项已通过相应的付款或贷记通知单关闭。发票被视为已完全结算。 | ||
| 为何重要 标志着单张发票的“订单到收款”周期圆满完成。这是衡量整体平均发票周期时间的主要结束事件。 获取方式 当 BSEG 表中的发票行项目填充了结清凭证 (AUGBL) 和结清日期 (AUGDT) 字段时发生。 捕获 event 发生在发票行项目在 BSEG 表中记录的结清日期 (AUGDT)。 事件类型 explicit | |||
| 发票已过账 | 发票已正式记录在应收账款明细账和总账中。此事件使发票具有法律约束力,并反映了客户所欠的债务。 | ||
| 为何重要 这是一个关键里程碑,标志着回款计时的正式开始。生成与过账之间的时间可以突出影响现金流的内部处理延迟。 获取方式 记录在 BKPF 表中。凭证编号 (BELNR) 的过账日期 (BUDAT) 标志着该事件。对于暂存凭证,这是其转换为已过账凭证的时间。 捕获 来自发票凭证在 BKPF 表中的过账日期 (BUDAT)。 事件类型 explicit | |||
| 已收到客户付款 | 已收到客户付款并作为现金收据或银行存款入账。这将创建一个独立的付款单据,尚未应用到特定发票。 | ||
| 为何重要 这是现金转换周期中的一个重要里程碑。从发票发送到收到付款的时间是应收账款周转天数 (DSO) 的主要组成部分。 获取方式 作为新凭证记录在 BKPF 和 BSEG 中,通常其凭证类型表示客户付款(如“DZ”)。过账日期 (BUDAT) 标志着该事件。 捕获 来自 BKPF 中客户付款凭证的过账日期。 事件类型 explicit | |||
| 已生成发票 | 标志着系统中计费单据的创建。当会计凭证抬头表 (BKPF) 中使用特定的发票凭证类型创建新条目时,即捕获此事件。 | ||
| 为何重要 这是整个开票流程的起点。分析从该事件开始的时间有助于衡量发票创建周期,也是计算应收账款周转天数 (DSO) 的基础。 获取方式 记录在 BKPF 表中。特定凭证编号 (BELNR) 的创建日期 (CPUDT) 和时间 (CPUTM) 标志着该事件。凭证类型 (BLART) 将其标识为发票。 捕获 来自发票凭证在 BKPF 表中的创建 timestamp (CPUDT)。 事件类型 explicit | |||
| 争议案例已创建 | 已针对发票发起正式争议,通常源于客户投诉。这记录在 SAP 争议管理系统中。 | ||
| 为何重要 识别存在延迟付款风险的发票,并突出导致客户不满的潜在问题。它标志着一个重要的异常处理流程的开始。 获取方式 从与发票会计凭证关联的争议案例表 (UDM_CASE) 中创建案例时捕获。 捕获 在用户通过交易 UDM_DISPUTE 创建争议案件时记录。 事件类型 explicit | |||
| 到达发票到期日 | 这是一个计算得出的 event,标志着根据付款条件发票应正式付款的日期。它不是由用户或系统执行的活动,而是一个关键的时间节点。 | ||
| 为何重要 对于分析付款行为和合规性至关重要。它是确定准时付款与逾期付款以及计算“准时付款率”KPI 的基准。 获取方式 通过将当前日期与净到期日进行比较得出。到期日可在字段 BSEG-ZFBDT 中找到,或根据基准日期和付款条件计算得出。 捕获 将系统日期与发票行项目 (BSEG) 中的净到期日字段进行比较。 事件类型 calculated | |||
| 发票已审批 | 代表发票的正式批准,允许其过账或发送给客户。这通常在暂存凭证转换为已过账凭证时推断得出。 | ||
| 为何重要 跟踪内部审批工作流,这是常见的瓶颈来源。分析此活动有助于识别审批缓慢的人员,从而为“发票审批流分析”仪表板提供支持。 获取方式 可通过单据从预制状态(在 VBKPF 中)到过账状态(在 BKPF 中)的转换来推断。或者,如果使用了 workflow 系统,这可能是 workflow 日志中的一个显式 event。 捕获 比较预制单据 (VBKPF) 的创建日期与最终凭证 (BKPF) 的过账日期。 事件类型 inferred | |||
| 发票已暂存 | 发票单据已保存为初步状态,尚未过账到总账。这通常在信息不完整或在最终过账前需要审核时使用。 | ||
| 为何重要 跟踪预过账步骤和潜在延迟。在暂存状态停留时间过长可能预示着数据质量问题或预审批流程中的瓶颈。 获取方式 暂存凭证存储在 VBKPF 表中。在此处创建并随后过账的凭证标志着该活动。 捕获 在使用 FV70 等交易保存暂存凭证时记录。 事件类型 explicit | |||
| 发票已核销 | 一种替代的最终状态,即发票被视为无法收回,未结金额针对坏账科目结清。这在没有客户付款的情况下关闭了发票。 | ||
| 为何重要 代表负面的流程结果和收入损失。跟踪这些事件有助于分析坏账原因并改进信用管理政策。 获取方式 通过分析发票的结清交易来推断。如果结清凭证过账到特定的坏账费用总账科目,则该发票被视为已核销。 捕获 当结清交易涉及过账到指定的坏账总账科目时推断。 事件类型 inferred | |||
| 发票已纠正 | 代表一项返工活动,即发现初始发票不正确并随后进行了冲销。这通过识别链接到原始发票的冲销凭证来捕获。 | ||
| 为何重要 突出流程低效和质量问题。高频的纠正操作预示着上游销售或计费数据存在问题,为“发票返工与错误率”仪表板提供支持。 获取方式 通过查找 BKPF-STBLG 指向原始凭证的冲销凭证来识别。该冲销凭证的创建即为事件。 捕获 在创建冲销凭证(例如通过 FB08)时记录。 事件类型 explicit | |||
| 已发出催款单 | 系统已针对逾期发票生成并向客户发送了催款通知或付款提醒。这从催款历史日志中捕获。 | ||
| 为何重要 帮助评估催收策略的有效性。分析从提醒到收到付款的时间是“催款有效性”KPI 的关键。 获取方式 记录在催款数据表中,具体为由催款运行(交易 F150)生成的 MHNK(催款数据抬头)和 MHND(催款数据行项目)。 捕获 在针对逾期项目执行催款运行 (F150) 时记录。 事件类型 explicit | |||
| 款项已核销至发票 | 收到的客户付款已与特定的未结发票匹配并应用,标记该项目待结清。这是将付款与债务关联的对账步骤。 | ||
| 为何重要 此活动对于衡量现金应用周期至关重要。现金应用延迟可能会扭曲真实的应收账款状态并隐藏可用现金。 获取方式 从结清交易(例如 F-32)推断,该交易会填充发票行项目中的结清字段。事件 timestamp 即为结清日期。 捕获 从发票行项目表 (BSEG) 中填充的结清日期 (AUGDT) 推断。 事件类型 inferred | |||
提取指南
步骤
- 访问 ABAP 编辑器: 登录您的 SAP ECC 系统。使用事务代码
SE38进入 ABAP 编辑器。 - 创建程序: 在程序字段中输入新程序的名称,例如
Z_PM_O2C_INVOICE_EXTRACT,然后点击“创建”按钮。提供描述性标题,并将程序类型设置为“可执行程序”。 - 定义选择屏幕: 在程序源代码中定义选择屏幕参数。这允许用户筛选待提取的 data。关键参数包括单据创建日期范围 (
S_ERDAT)、公司代码 (S_BUKRS) 和计费单据类型 (S_VBTYP)。 - 定义 data 结构: 声明一个用于存放最终 event log data 的内表结构。该结构必须包含
InvoiceNumber、ActivityName、EventTime以及推荐属性,如UserName、BillingDocumentType、CustomerNumber、CompanyCode和TotalInvoiceAmount。 - 实现 data 选择逻辑: 编写核心 ABAP 逻辑来选择 data。首先,根据用户的选择屏幕输入,从表
VBRK和BKPF中选择主要计费单据,并将其存入临时内表。 - 提取活动: 循环遍历初始计费单据列表。对于每张单据,从各个表中进行后续选择以识别所需的 13 个活动。例如,查询表
NAST以获取“发票已发送给客户”event,查询BSEG获取结清信息(“发票已结清”、“付款已应用”),查询MHNK获取催收 data(“已发出付款提醒”)。 - 构建 event log 表: 对于上一步中发现的每个活动,在最终的 event log 内表中填充一条新记录。确保
InvoiceNumber、ActivityName、EventTime和其他属性从源表中正确映射。 - 写入应用服务器: 循环结束且 event log 表填充完毕后,使用
OPEN DATASET、LOOP AT... TRANSFER和CLOSE DATASET语句将内表内容写入 SAP 应用服务器上的平面文件。指定一个可访问的逻辑文件路径。 - 获取文件: 使用事务代码
AL11浏览应用服务器目录并定位生成的文件。联系您的 SAP Basis 团队,将文件从服务器下载到本地计算机或共享网络位置。 - 最终格式化: 打开下载的文件,确认它是带有标题行的逗号分隔值 (CSV) 文件。确保文件以 UTF-8 编码保存,以便与 ProcessMind 的 upload 兼容。
配置
- 先决条件: 拥有创建和执行 ABAP 程序 (事务代码 SE38) 的权限。拥有读取 FI 和 SD 模块表的授权,包括
VBRK、VBRP、BKPF、BSEG、NAST、MHNK和UDM_CASE_ATTR00(用于争议管理)。 - 日期范围选择: 程序应设置强制性的日期范围参数,通常基于单据创建日期(VBRK/BKPF 中的
ERDAT)。对于初始提取,建议选择 3-6 个月的范围以保持 data 集大小适中。 - 关键筛选条件: 务必按公司代码 (
BUKRS) 进行筛选以限制提取范围。同时强烈建议按计费单据类型(VBRK 中的VBTYP)或会计凭证类型(BKPF 中的BLART)进行筛选,以仅包含相关的发票类型(例如标准会计发票 'RV'),并排除红利通知单或其他单据。 - 性能考量: 对于涵盖数月以上的大规模 data 集,应作为后台作业执行程序以避免会话超时。应优化 ABAP 逻辑以使用索引表读取,避免在嵌套循环中进行数据库选择。首选方法是将 data 先读取到内表中,然后再进行处理。
- 输出文件配置: ABAP 代码必须指定应用服务器上的输出文件路径以及 CSV 文件的分隔符(通常为逗号或分号)。确保该路径是全局配置且可访问的目录。
a 查询示例 abap
REPORT Z_PM_O2C_INVOICE_EXTRACT.
*&---------------------------------------------------------------------*
*& Tables
*&---------------------------------------------------------------------*
TABLES: VBRK, BKPF.
*&---------------------------------------------------------------------*
*& Type Definitions for Event Log Output
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
invoicenumber TYPE vbrk-vbeln,
activityname TYPE string,
eventtime TYPE timestamp,
username TYPE xubname,
billingdocumenttype TYPE vbrk-vbtyp,
customernumber TYPE vbrk-kunnr,
companycode TYPE vbrk-bukrs,
totalinvoiceamount TYPE vbrk-netwr,
END OF ty_event_log.
*&---------------------------------------------------------------------*
*& Data Declarations
*&---------------------------------------------------------------------*
DATA: gt_event_log TYPE TABLE OF ty_event_log,
gs_event_log TYPE ty_event_log.
DATA: BEGIN OF gs_invoice,
vbeln TYPE vbrk-vbeln, " SD Doc (Invoice)
awkey TYPE bkpf-awkey, " Accounting Doc Reference Key
bukrs TYPE vbrk-bukrs, " Company Code
kunnr TYPE vbrk-kunnr, " Customer
vbtyp TYPE vbrk-vbtyp, " SD Doc Type
netwr TYPE vbrk-netwr, " Net Value
waerk TYPE vbrk-waerk, " Currency
fkdat TYPE vbrk-fkdat, " Billing Date
erdat TYPE vbrk-erdat, " Creation Date
erzet TYPE vbrk-erzet, " Creation Time
ernam TYPE vbrk-ernam, " Creator
belnr TYPE bkpf-belnr, " Acct Doc
gjahr TYPE bkpf-gjahr, " Fiscal Year
cpudt TYPE bkpf-cpudt, " Acct Doc Entry Date
cputm TYPE bkpf-cputm, " Acct Doc Entry Time
usnam TYPE bkpf-usnam, " Acct Doc User
stblg TYPE bkpf-stblg, " Reversal Doc
END OF gs_invoice.
DATA: gt_invoices LIKE TABLE OF gs_invoice.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_erdat FOR vbrk-erdat OBLIGATORY,
s_bukrs FOR vbrk-bukrs OBLIGATORY,
s_vbtyp FOR vbrk-vbtyp.
PARAMETERS: p_path TYPE string DEFAULT '/usr/sap/trans/tmp/invoice_extract.csv' OBLIGATORY.
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
" 1. Select base set of invoices
SELECT vbrk~vbeln, vbrk~bukrs, vbrk~kunnr, vbrk~vbtyp, vbrk~netwr, vbrk~waerk,
vbrk~fkdat, vbrk~erdat, vbrk~erzet, vbrk~ernam,
bkpf~belnr, bkpf~gjahr, bkpf~cpudt, bkpf~cputm, bkpf~usnam, bkpf~stblg, bkpf~awkey
INTO CORRESPONDING FIELDS OF TABLE gt_invoices
FROM vbrk
INNER JOIN bkpf ON bkpf~awkey = vbrk~vbeln AND bkpf~awtyp = 'VBRK'
WHERE vbrk~erdat IN s_erdat
AND vbrk~bukrs IN s_bukrs
AND vbrk~vbtyp IN s_vbtyp.
IF gt_invoices IS INITIAL.
MESSAGE 'No invoices found for the selected criteria.' TYPE 'I'.
RETURN.
ENDIF.
LOOP AT gt_invoices INTO gs_invoice.
CLEAR gs_event_log.
gs_event_log-invoicenumber = gs_invoice-vbeln.
gs_event_log-billingdocumenttype = gs_invoice-vbtyp.
gs_event_log-customernumber = gs_invoice-kunnr.
gs_event_log-companycode = gs_invoice-bukrs.
gs_event_log-totalinvoiceamount = gs_invoice-netwr.
" Activity: Invoice Generated (using accounting doc creation)
gs_event_log-activityname = 'Invoice Generated'.
gs_event_log-username = gs_invoice-usnam.
CONCATENATE gs_invoice-cpudt gs_invoice-cputm INTO DATA(lv_ts_gen).
CONVERT DATE gs_invoice-cpudt TIME gs_invoice-cputm INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
" Activity: Invoice Posted (same as generated for non-parked docs)
gs_event_log-activityname = 'Invoice Posted'.
gs_event_log-username = gs_invoice-usnam.
CONVERT DATE gs_invoice-cpudt TIME gs_invoice-cputm INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
" Activity: Invoice Approved (inferred by posting)
gs_event_log-activityname = 'Invoice Approved'.
APPEND gs_event_log TO gt_event_log.
" Activity: Invoice Sent To Customer
SELECT SINGLE addat, aduhr FROM nast
INTO (DATA(lv_nast_date), DATA(lv_nast_time))
WHERE kappl = 'V3' AND objky = gs_invoice-vbeln AND vszst > '0'.
IF sy-subrc = 0.
gs_event_log-activityname = 'Invoice Sent To Customer'.
gs_event_log-username = sy-uname.
CONVERT DATE lv_nast_date TIME lv_nast_time INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
ENDIF.
" Activity: Invoice Corrected / Reversed
IF gs_invoice-stblg IS NOT INITIAL.
SELECT SINGLE cpudt, cputm, usnam FROM bkpf
INTO (DATA(lv_rev_date), DATA(lv_rev_time), DATA(lv_rev_user))
WHERE belnr = gs_invoice-stblg AND gjahr = gs_invoice-gjahr.
IF sy-subrc = 0.
gs_event_log-activityname = 'Invoice Corrected'.
gs_event_log-username = lv_rev_user.
CONVERT DATE lv_rev_date TIME lv_rev_time INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
" Activity: Payment Applied, Cleared, Due Date, Written Off (from BSEG)
SELECT SINGLE augdt, augbl, zfBDT, hkont FROM bseg
INTO (DATA(lv_augdt), DATA(lv_augbl), DATA(lv_zfbdt), DATA(lv_hkont))
WHERE bukrs = gs_invoice-bukrs
AND belnr = gs_invoice-belnr
AND gjahr = gs_invoice-gjahr
AND koart = 'D'. " Customer line
IF sy-subrc = 0.
" Due Date Reached (Calculated event)
IF lv_zfbdt IS NOT INITIAL.
gs_event_log-activityname = 'Invoice Due Date Reached'.
gs_event_log-username = 'System'.
CONVERT DATE lv_zfbdt INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
ENDIF.
" Cleared, Applied, Write-Off
IF lv_augdt IS NOT INITIAL.
SELECT SINGLE usnam, cpudt, cputm, blart FROM bkpf
INTO (DATA(lv_clear_user), DATA(lv_clear_date), DATA(lv_clear_time), DATA(lv_clear_type))
WHERE belnr = lv_augbl AND bukrs = gs_invoice-bukrs.
IF sy-subrc = 0.
gs_event_log-username = lv_clear_user.
CONVERT DATE lv_clear_date TIME lv_clear_time INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
IF lv_clear_type = 'DZ'. " Standard Customer Payment
gs_event_log-activityname = 'Customer Payment Received'. APPEND gs_event_log TO gt_event_log.
gs_event_log-activityname = 'Payment Applied To Invoice'. APPEND gs_event_log TO gt_event_log.
gs_event_log-activityname = 'Invoice Cleared'. APPEND gs_event_log TO gt_event_log.
ELSE. " Assuming other clearing doc types could be write-offs
gs_event_log-activityname = 'Invoice Written Off'.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
" Activity: Payment Reminder Issued (Dunning)
SELECT COUNT(*) FROM mhnk WHERE kunnr = gs_invoice-kunnr AND bukrs = gs_invoice-bukrs AND lafdn > gs_invoice-cpudt.
IF sy-subrc = 0 AND sy-dbcnt > 0.
SELECT SINGLE lafdn FROM mhnk
INTO DATA(lv_dunning_date)
WHERE kunnr = gs_invoice-kunnr AND bukrs = gs_invoice-bukrs AND lafdn > gs_invoice-cpudt.
gs_event_log-activityname = 'Payment Reminder Issued'.
gs_event_log-username = 'System'.
CONVERT DATE lv_dunning_date INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
ENDIF.
" Activity: Invoice Parked (Example from VBKPF, may require system specific logic)
SELECT SINGLE cpudt, cputm, usnam FROM vbkpf
INTO (DATA(lv_park_date), DATA(lv_park_time), DATA(lv_park_user))
WHERE awkey = gs_invoice-vbeln AND awsys = 'LOG' AND bstat = 'V'.
IF sy-subrc = 0.
gs_event_log-activityname = 'Invoice Parked'.
gs_event_log-username = lv_park_user.
CONVERT DATE lv_park_date TIME lv_park_time INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
ENDIF.
" Activity: Dispute Case Created (Requires Dispute Management module)
SELECT SINGLE create_date, create_time, create_user FROM udm_case_attr00
INTO (DATA(lv_disp_date), DATA(lv_disp_time), DATA(lv_disp_user))
WHERE [Your logic to link invoice to dispute case, e.g., via a custom field or object link].
IF sy-subrc = 0.
gs_event_log-activityname = 'Dispute Case Created'.
gs_event_log-username = lv_disp_user.
CONVERT DATE lv_disp_date TIME lv_disp_time INTO TIME STAMP gs_event_log-eventtime TIME ZONE sy-zonlo.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
*&---------------------------------------------------------------------*
*& Write data to file
*&---------------------------------------------------------------------*
OPEN DATASET p_path FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
IF sy-subrc <> 0.
MESSAGE 'Error opening file.' TYPE 'E'.
ENDIF.
" Header
DATA(lv_header) = 'InvoiceNumber,ActivityName,EventTime,UserName,BillingDocumentType,CustomerNumber,CompanyCode,TotalInvoiceAmount'.
TRANSFER lv_header TO p_path.
LOOP AT gt_event_log INTO gs_event_log.
DATA(lv_line) = |
{ gs_event_log-invoicenumber }|
,{ gs_event_log-activityname }|
,{ gs_event_log-eventtime }|
,{ gs_event_log-username }|
,{ gs_event_log-billingdocumenttype }|
,{ gs_event_log-customernumber }|
,{ gs_event_log-companycode }|
,{ gs_event_log-totalinvoiceamount }|.
TRANSFER lv_line TO p_path.
ENDLOOP.
CLOSE DATASET p_path.
WRITE: 'Extraction complete. File created at:', p_path. 步骤
- 先决条件与权限: 确保您的数据库用户对必要的 SAP ECC 表(包括 VBRK、BKPF、BSAD、NAST、CDHDR、CDPOS、SCASE 以及查询中指定的其他表)具有只读访问权限。此类权限通常仅授予系统管理员或特定的数据分析团队。
- 连接数据库: 使用标准的 SQL 客户端工具(如 DBeaver、Oracle SQL Developer 或 Microsoft SQL Server Management Studio)建立与 SAP ECC 数据库的连接。
- 准备 SQL 查询: 将“查询”部分提供的完整 SQL 查询复制到 SQL 客户端的编辑器中。
- 自定义占位符: 查询包含多个占位符,您必须将其替换为特定于您环境的值。包括:
'YYYYMMDD': 将所有实例替换为您所需分析期间的开始和结束日期。将 data 过滤到可管理的范围至关重要。'XXXX': 替换为您希望分析的具体公司代码。[Your Invoice Output Type]: 指定用于向客户发送发票的输出类型代码,例如 'RD00'。[Your Bad Debt G/L Account]: 输入用于核销坏账发票的总账科目编号。[Your Dispute Case Invoice Attribute]: 指定在您的争议管理配置中用于存储发票编号的属性名称,例如 'INVOICE_ID'。
- 检查 timestamp 函数: 查询使用通用的
CAST(CONCAT(date_field, time_field) AS TIMESTAMP)语法。您可能需要根据具体的数据库系统进行调整,例如 Oracle 使用TO_TIMESTAMP,SQL Server 使用DATETIMEFROMPARTS。 - 执行查询: 运行修改后的查询。根据 SAP 表的大小和选定的日期范围,执行可能需要较长时间。
- 检查结果: 查询完成后,检查输出以确保包含所需的列:InvoiceNumber、ActivityName、EventTime 以及推荐的属性。检查是否有错误或空结果。
- 导出为 CSV: 将 SQL 客户端的完整结果集导出为 CSV 文件。确保文件使用 UTF-8 编码,以防止特殊字符出现问题。
- 准备 upload: 在 upload 到 Process Mining 工具之前,确认 CSV 列标题与要求的属性名称完全匹配,例如
InvoiceNumber、ActivityName、EventTime、UserName。
配置
- 数据库连接: 需要直接、只读的 SQL 连接到底层 SAP ECC 数据库。此方法将完全绕过 SAP 应用层。
- 权限: 数据库用户必须对查询中涉及的所有表(涵盖 FI、SD 以及可能涉及的 FSCM 模块)拥有
SELECT权限。 - 日期范围: 为确保合理的性能和控制数据量,必须按特定日期范围筛选查询。我们建议最初选择 3 到 6 个月的数据量。日期筛选占位符
'YYYYMMDD'必须在查询的多个部分进行设置。 - 公司代码筛选: 查询设计为按公司代码 (
BUKRS) 进行筛选。一次分析一个或少数几个公司代码是标准做法。 - 凭证类型配置: 识别诸如发票更正、核销或已发送单据等 event 的逻辑取决于标准 SAP 配置。如果贵组织使用自定义凭证类型 (
BLART)、输出类型 (KSCHL) 或总账科目,则可能需要调整查询。 - 性能考量: 在 SAP 生产系统中执行此查询可能会消耗大量资源并影响业务性能。强烈建议在非高峰时段运行大规模数据提取,或针对专用的报告数据库副本运行。
a 查询示例 sql
WITH InvoiceBase AS (
SELECT
VBRK.VBELN AS InvoiceNumber,
VBRK.FKART AS BillingDocumentType,
VBRK.KUNRG AS CustomerNumber,
VBRK.BUKRS AS CompanyCode,
VBRK.NETWR AS TotalInvoiceAmount,
VBRK.ERNAM AS CreatorName,
VBRK.ERDAT AS CreationDate,
VBRK.ERZET AS CreationTime
FROM VBRK
WHERE VBRK.ERDAT BETWEEN '20230101' AND '20231231' -- Filter by Invoice Creation Date
AND VBRK.BUKRS IN ('1000') -- Filter by Company Code
AND VBRK.FKART NOT IN ('S1', 'S2') -- Exclude cancelled invoices
)
-- 1. Invoice Generated
SELECT
ib.InvoiceNumber,
'Invoice Generated' AS ActivityName,
CAST(CONCAT(ib.CreationDate, ib.CreationTime) AS TIMESTAMP) AS EventTime,
ib.CreatorName AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
ib.CompanyCode,
ib.TotalInvoiceAmount
FROM InvoiceBase ib
UNION ALL
-- 2. Invoice Parked
SELECT
SUBSTRING(b.AWKEY, 1, 10) AS InvoiceNumber,
'Invoice Parked' AS ActivityName,
CAST(CONCAT(b.CPUDT, b.CPUTM) AS TIMESTAMP) AS EventTime,
b.USNAM AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
b.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BKPF b
JOIN InvoiceBase ib ON SUBSTRING(b.AWKEY, 1, 10) = ib.InvoiceNumber
WHERE b.AWTYP = 'VBRK' AND b.BSTAT = 'V' AND b.CPUDT BETWEEN '20230101' AND '20231231'
UNION ALL
-- 3. Invoice Posted
SELECT
SUBSTRING(b.AWKEY, 1, 10) AS InvoiceNumber,
'Invoice Posted' AS ActivityName,
CAST(CONCAT(b.CPUDT, b.CPUTM) AS TIMESTAMP) AS EventTime,
b.USNAM AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
b.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BKPF b
JOIN InvoiceBase ib ON SUBSTRING(b.AWKEY, 1, 10) = ib.InvoiceNumber
WHERE b.AWTYP = 'VBRK' AND b.BSTAT = '' AND b.CPUDT BETWEEN '20230101' AND '20231231'
UNION ALL
-- 4. Invoice Approved (from Parked to Posted)
SELECT
SUBSTRING(h.OBJECTID, 4, 10) AS InvoiceNumber,
'Invoice Approved' as ActivityName,
CAST(CONCAT(h.UDATE, h.UTIME) AS TIMESTAMP) AS EventTime,
h.USERNAME AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
ib.CompanyCode,
ib.TotalInvoiceAmount
FROM CDHDR h
JOIN CDPOS p ON h.MANDANT = p.MANDANT AND h.OBJECTCLAS = p.OBJECTCLAS AND h.OBJECTID = p.OBJECTID AND h.CHANGENR = p.CHANGENR
JOIN InvoiceBase ib ON SUBSTRING(h.OBJECTID, 4, 10) = ib.InvoiceNumber
WHERE h.OBJECTCLAS = 'BELEGV'
AND p.TABNAME = 'BKPF'
AND p.FNAME = 'BSTAT'
AND p.VALUE_OLD = 'V'
AND p.VALUE_NEW = ' '
AND h.UDATE BETWEEN '20230101' AND '20231231'
UNION ALL
-- 5. Invoice Sent To Customer
SELECT
n.OBJKY AS InvoiceNumber,
'Invoice Sent To Customer' AS ActivityName,
CAST(CONCAT(n.DATVR, n.UHRVR) AS TIMESTAMP) AS EventTime,
n.VSTAT AS UserName, -- User who processed is not directly available, using processing status as a proxy
ib.BillingDocumentType,
ib.CustomerNumber,
ib.CompanyCode,
ib.TotalInvoiceAmount
FROM NAST n
JOIN InvoiceBase ib ON n.OBJKY = ib.InvoiceNumber
WHERE n.KSCHL = '[Your Invoice Output Type]' -- E.g., 'RD00'
AND n.VSTAT = '1' -- Processed successfully
AND n.DATVR BETWEEN '20230101' AND '20231231'
UNION ALL
-- 6. Invoice Corrected (Reversed)
SELECT
SUBSTRING(orig_doc.AWKEY, 1, 10) AS InvoiceNumber,
'Invoice Corrected' AS ActivityName,
CAST(CONCAT(rev_doc.CPUDT, rev_doc.CPUTM) AS TIMESTAMP) AS EventTime,
rev_doc.USNAM AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
rev_doc.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BKPF orig_doc
JOIN BKPF rev_doc ON orig_doc.STBLG = rev_doc.BELNR AND orig_doc.BUKRS = rev_doc.BUKRS AND orig_doc.GJAHR = rev_doc.STJAH
JOIN InvoiceBase ib ON SUBSTRING(orig_doc.AWKEY, 1, 10) = ib.InvoiceNumber
WHERE orig_doc.AWTYP = 'VBRK' AND orig_doc.STBLG IS NOT NULL AND rev_doc.CPUDT BETWEEN '20230101' AND '20231231'
UNION ALL
-- 7. Invoice Due Date Reached
SELECT
SUBSTRING(b.AWKEY, 1, 10) AS InvoiceNumber,
'Invoice Due Date Reached' AS ActivityName,
CAST(CONCAT(bs.ZFBDT, '000000') AS TIMESTAMP) AS EventTime,
'System' AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
b.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BSEG bs
JOIN BKPF b ON bs.MANDT = b.MANDT AND bs.BUKRS = b.BUKRS AND bs.BELNR = b.BELNR AND bs.GJAHR = b.GJAHR
JOIN InvoiceBase ib ON SUBSTRING(b.AWKEY, 1, 10) = ib.InvoiceNumber
WHERE b.AWTYP = 'VBRK' AND bs.KOART = 'D' AND bs.ZFBDT BETWEEN '20230101' AND '20231231'
UNION ALL
-- 8. Payment Reminder Issued
SELECT
SUBSTRING(b.AWKEY, 1, 10) AS InvoiceNumber,
'Payment Reminder Issued' AS ActivityName,
CAST(CONCAT(h.LAUFD, '000000') AS TIMESTAMP) AS EventTime,
h.LAUFI AS UserName, -- Dunning Run ID
ib.BillingDocumentType,
ib.CustomerNumber,
d.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM MHND d
JOIN MHNK h ON d.MANDT = h.MANDT AND d.LAUFD = h.LAUFD AND d.LAUFI = h.LAUFI
JOIN BKPF b ON d.MANDT = b.MANDT AND d.BUKRS = b.BUKRS AND d.BELNR = b.BELNR AND d.GJAHR = b.GJAHR
JOIN InvoiceBase ib ON SUBSTRING(b.AWKEY, 1, 10) = ib.InvoiceNumber
WHERE h.LAUFD BETWEEN '20230101' AND '20231231'
UNION ALL
-- 9. Dispute Case Created
SELECT
attr.ATTR_VALUE AS InvoiceNumber,
'Dispute Case Created' AS ActivityName,
sc.CREATE_TIME AS EventTime,
sc.CREATED_BY AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
ib.CompanyCode,
ib.TotalInvoiceAmount
FROM SCMG_T_CASE_ATTR attr
JOIN SCASE sc ON attr.CASE_GUID = sc.CASE_GUID
JOIN InvoiceBase ib ON attr.ATTR_VALUE = ib.InvoiceNumber
WHERE attr.ATTR_NAME = '[Your Dispute Case Invoice Attribute]' -- e.g., 'INVOICE_ID'
AND CAST(sc.CREATE_TIME AS DATE) BETWEEN '20230101' AND '20231231'
UNION ALL
-- 10, 11, 12. Clearing Events (Payment, Clearing, Write-Off)
SELECT
InvoiceNumber,
ActivityName,
EventTime,
UserName,
BillingDocumentType,
CustomerNumber,
CompanyCode,
TotalInvoiceAmount
FROM (
SELECT
bsad.XBLNR AS InvoiceNumber,
CASE
WHEN clearing_item.HKONT = '[Your Bad Debt G/L Account]' THEN 'Invoice Written Off'
ELSE 'Customer Payment Received'
END AS ActivityName,
CAST(CONCAT(clearing_doc.CPUDT, clearing_doc.CPUTM) AS TIMESTAMP) AS EventTime,
clearing_doc.USNAM AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
bsad.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BSAD bsad
JOIN InvoiceBase ib ON bsad.XBLNR = ib.InvoiceNumber
JOIN BKPF clearing_doc ON bsad.MANDT = clearing_doc.MANDT AND bsad.BUKRS = clearing_doc.BUKRS AND bsad.AUGBL = clearing_doc.BELNR AND bsad.AUGGJ = clearing_doc.GJAHR
LEFT JOIN BSEG clearing_item ON clearing_doc.MANDT = clearing_item.MANDT AND clearing_doc.BUKRS = clearing_item.BUKRS AND clearing_doc.BELNR = clearing_item.BELNR AND clearing_doc.GJAHR = clearing_item.GJAHR AND clearing_item.HKONT = '[Your Bad Debt G/L Account]' -- e.g. '148000'
WHERE bsad.AUGDT BETWEEN '20230101' AND '20231231' AND bsad.UMSKZ = ''
UNION ALL
SELECT
bsad.XBLNR AS InvoiceNumber,
'Payment Applied To Invoice' AS ActivityName,
CAST(CONCAT(bsad.AUGDT, '000000') AS TIMESTAMP) AS EventTime,
clearing_doc.USNAM AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
bsad.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BSAD bsad
JOIN InvoiceBase ib ON bsad.XBLNR = ib.InvoiceNumber
JOIN BKPF clearing_doc ON bsad.MANDT = clearing_doc.MANDT AND bsad.BUKRS = clearing_doc.BUKRS AND bsad.AUGBL = clearing_doc.BELNR AND bsad.AUGGJ = clearing_doc.GJAHR
WHERE bsad.AUGDT BETWEEN '20230101' AND '20231231' AND bsad.UMSKZ = ''
UNION ALL
SELECT
bsad.XBLNR AS InvoiceNumber,
'Invoice Cleared' AS ActivityName,
CAST(CONCAT(bsad.AUGDT, '235959') AS TIMESTAMP) AS EventTime, -- Add time to separate from 'Payment Applied'
clearing_doc.USNAM AS UserName,
ib.BillingDocumentType,
ib.CustomerNumber,
bsad.BUKRS AS CompanyCode,
ib.TotalInvoiceAmount
FROM BSAD bsad
JOIN InvoiceBase ib ON bsad.XBLNR = ib.InvoiceNumber
JOIN BKPF clearing_doc ON bsad.MANDT = clearing_doc.MANDT AND bsad.BUKRS = clearing_doc.BUKRS AND bsad.AUGBL = clearing_doc.BELNR AND bsad.AUGGJ = clearing_doc.GJAHR
WHERE bsad.AUGDT BETWEEN '20230101' AND '20231231' AND bsad.UMSKZ = ''
) AS ClearingEvents 步骤
- 先决条件: 确保您拥有带认证 SAP 连接器的授权 ETL 工具(如带 SAP 连接器的 Informatica PowerCenter、Talend 等)。验证您是否拥有具有读取必要财务、销售和系统表(BKPF、BSEG、VBRK、NAST、MHNK、UDM_CASE_ATTR00、CDHDR、CDPOS)权限的 SAP 用户凭据。
- 建立 SAP 连接: 在 ETL 工具中创建到 SAP ECC 系统的新连接。配置连接详情,包括应用服务器、系统编号、客户端、用户和密码。测试连接以确保成功。
- 定义 data 源: 对于要提取的每个活动,在 ETL 作业中定义相应的 SAP 表作为 data 源。例如,添加 VBRK 用于发票生成,添加 BKPF 用于过账 event,添加 NAST 用于客户沟通。
- 为每个活动构建提取逻辑: 为 13 个所需活动中的每一个创建独立的数据流或转换。在每个流中,应用过滤器选择相关记录。例如,按公司代码 (BUKRS)、单据类型 (BLART) 和特定日期范围(如创建日期 ERDAT)进行过滤。
- 映射字段与转换 data: 在每个数据流中,将源 SAP 表字段映射到目标 event log 结构:InvoiceNumber、ActivityName、EventTime、UserName 和其他推荐属性。使用转换逻辑为每个流硬编码 'ActivityName',并正确格式化日期和 timestamp。
- 处理复杂活动: 对于诸如“到达发票付款截止日期”之类的计算 event,请使用基准付款日期 (ZFBDT) 和付款条件逻辑来计算截止日期,或者直接从 BSEG 提取净到期日 (NETDT)。对于从变更日志派生的 event(如“发票已审批”),您可能需要根据单据编号和日期关联 BKPF 和 CDHDR/CDPOS 表。
- 合并活动 data: 在 ETL 工具中使用“Union”或“Merge”转换,将所有 13 个独立数据流的输出合并为单个 data 集。在合并之前,确保所有流的列名和 data 类型保持一致。
- 配置目标位置: 定义 event log 的最终输出目标。这可以是平面文件 (CSV)、数据库表或指向暂存区的直接连接。
- 设置提取计划: 配置提取的日期范围参数。对于初始加载,您可能会提取 6-12 个月的数据。对于后续的增量加载,请将作业配置为提取自上次运行日期以来的数据。
- 执行与导出: 运行 ETL 作业。完成后,检查输出文件以确保其符合要求的格式。最终输出应为一个 CSV 文件,每行代表一个唯一的 event,可随时 upload 至 ProcessMind。
配置
- SAP 连接: 需要到目标 SAP ECC 系统的主机连接。SAP 用户需要 RFC 访问权限,以及对 VBRK、BKPF、BSEG、NAST 和查询中指定的其他表的读取权限。
- ETL 工具许可: 必须拥有商业 ETL 工具及其特定 SAP 连接器的有效许可。
- 日期范围: 建议提取 3 到 6 个月的数据,以确保分析样本具有代表性,同时不会造成过大的系统负载。使用可配置的参数设置开始和结束日期。
- 关键筛选条件: 务必按公司代码 (BUKRS) 筛选以限制提取范围。此外,筛选相关的计费单据类型 (VBRK-FKART) 和会计凭证类型 (BKPF-BLART) 也至关重要,以便仅包含标准发票,排除红利通知单或内部凭证等其他类型。
- 性能: 从 BSEG 等大表中提取数据可能较慢。请使用选择性筛选条件,避免提取不必要的字段,并将提取任务安排在非高峰时段,以尽量减少对 SAP 源系统的性能影响。
a 查询示例 config
// ETL Data Extraction Logic for SAP Order-to-Cash Invoicing
// This represents the configuration logic within a graphical ETL tool.
// == Global Parameters ==
// $StartDate: '[Start Date]' (e.g., '2023-01-01')
// $EndDate: '[End Date]' (e.g., '2023-06-30')
// $CompanyCodes: '[Company Code(s)]' (e.g., '1000', '2000')
// $BillingDocTypes: '[Billing Document Type(s)]' (e.g., 'F1', 'F2')
// == Source 1: Invoice Generated ==
// Tables: VBRK
DATA_SOURCE generated_invoices FROM VBRK WHERE
ERDAT >= $StartDate AND ERDAT <= $EndDate
AND BUKRS IN ($CompanyCodes)
AND FKART IN ($BillingDocTypes)
MAP {
InvoiceNumber: VBELN,
ActivityName: 'Invoice Generated',
EventTime: ERDAT + ERZET, // Combine date and time
UserName: ERNAM,
BillingDocumentType: FKART,
CustomerNumber: KUNAG,
CompanyCode: BUKRS,
TotalInvoiceAmount: NETWR
}
// == Source 2: Invoice Posted ==
// Tables: BKPF joined with VBRK
DATA_SOURCE posted_invoices FROM BKPF as A
INNER JOIN VBRK as B ON (A.AWKEY = B.VBELN AND A.AWTYP = 'VBRK')
WHERE A.BUDAT >= $StartDate AND A.BUDAT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND A.BSTAT = ' '
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Posted',
EventTime: A.BUDAT + A.CPUTM, // Posting date and entry time
UserName: A.USNAM,
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 3: Invoice Parked ==
// Tables: BKPF joined with VBRK
DATA_SOURCE parked_invoices FROM BKPF as A
INNER JOIN VBRK as B ON (A.AWKEY = B.VBELN AND A.AWTYP = 'VBRK')
WHERE A.CPUDT >= $StartDate AND A.CPUDT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND A.BSTAT = 'V'
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Parked',
EventTime: A.CPUDT + A.CPUTM,
UserName: A.USNAM,
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 4: Invoice Approved (Transition from Parked to Posted) ==
// Tables: BKPF joined with VBRK
DATA_SOURCE approved_invoices FROM BKPF as A
INNER JOIN VBRK as B ON (A.AWKEY = B.VBELN AND A.AWTYP = 'VBRK')
WHERE A.BUDAT >= $StartDate AND A.BUDAT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND A.BSTAT = ' '
AND EXISTS (SELECT 1 FROM VBELEGV C WHERE C.BELNR = A.BELNR) // Check if it was ever parked
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Approved',
EventTime: A.BUDAT + A.CPUTM, // Use posting date as approval date
UserName: A.USNAM,
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 5: Invoice Sent To Customer ==
// Tables: NAST joined with VBRK
DATA_SOURCE sent_invoices FROM NAST as A
INNER JOIN VBRK as B ON (A.OBJKY = B.VBELN)
WHERE A.ERDAT >= $StartDate AND A.ERDAT <= $EndDate
AND B.BUKRS IN ($CompanyCodes)
AND A.VSTAT = '1' // Successfully processed
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Sent To Customer',
EventTime: A.ERDAT + A.ERUHR,
UserName: A.USNAM,
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: B.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 6: Invoice Corrected (Reversed) ==
// Tables: VBRK (for the reversal document)
DATA_SOURCE corrected_invoices FROM VBRK as A
WHERE A.ERDAT >= $StartDate AND A.ERDAT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND A.SFAKN <> '' // SFAKN is the original cancelled invoice
MAP {
InvoiceNumber: A.SFAKN, // Case ID is the original invoice
ActivityName: 'Invoice Corrected',
EventTime: A.ERDAT + A.ERZET,
UserName: A.ERNAM,
BillingDocumentType: A.FKART,
CustomerNumber: A.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: NULL // Amount belongs to the reversal doc, not original
}
// == Source 7: Invoice Due Date Reached ==
// Tables: BSEG joined with VBRK
DATA_SOURCE due_invoices FROM BSEG as A
INNER JOIN BKPF as H ON (A.BUKRS = H.BUKRS AND A.BELNR = H.BELNR AND A.GJAHR = H.GJAHR)
INNER JOIN VBRK as B ON (H.AWKEY = B.VBELN AND H.AWTYP = 'VBRK')
WHERE A.NETDT >= $StartDate AND A.NETDT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND A.KOART = 'D' // Customer line item
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Due Date Reached',
EventTime: A.NETDT, // Net due date
UserName: 'System',
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 8: Payment Reminder Issued ==
// Tables: MHNK, MHND, VBRK
DATA_SOURCE reminders FROM MHNK as A
INNER JOIN MHND as D ON (A.LAUFD = D.LAUFD AND A.LAUFI = D.LAUFI)
INNER JOIN VBRK as B ON (SUBSTRING(D.XBLNR, 1, 10) = B.VBELN) // XBLNR may need parsing
WHERE A.LAUFD >= $StartDate AND A.LAUFD <= $EndDate
AND D.BUKRS IN ($CompanyCodes)
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Payment Reminder Issued',
EventTime: A.LAUFD, // Dunning date
UserName: A.IDAPS,
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: D.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 9: Dispute Case Created ==
// Tables: UDM_CASE_ATTR00
DATA_SOURCE disputes FROM UDM_CASE_ATTR00 as A
WHERE A.CREATE_TIMESTAMP >= $StartDate // Timestamp format may vary
AND A.FIN_COMP_CODE IN ($CompanyCodes)
AND A.PROCESS = 'FIN_FSCM_DIS'
MAP {
InvoiceNumber: A.BILL_DOC_ID,
ActivityName: 'Dispute Case Created',
EventTime: A.CREATE_TIMESTAMP,
UserName: A.CREATE_USER,
BillingDocumentType: NULL,
CustomerNumber: A.BP_NUMBER,
CompanyCode: A.FIN_COMP_CODE,
TotalInvoiceAmount: A.DISPUTED_AMOUNT
}
// == Source 10: Customer Payment Received ==
// Tables: BKPF
DATA_SOURCE payments FROM BKPF
WHERE BUDAT >= $StartDate AND BUDAT <= $EndDate
AND BUKRS IN ($CompanyCodes)
AND BLART = 'DZ' // Example for Customer Payment
MAP {
InvoiceNumber: NULL, // Invoice not yet known
ActivityName: 'Customer Payment Received',
EventTime: BUDAT + CPUTM,
UserName: USNAM,
BillingDocumentType: NULL,
CustomerNumber: NULL, // Requires join to BSEG to get customer
CompanyCode: BUKRS,
TotalInvoiceAmount: NULL
}
// == Source 11 & 12: Payment Applied To Invoice & Invoice Cleared ==
// Tables: BSEG joined with VBRK
DATA_SOURCE cleared_items FROM BSEG as A
INNER JOIN BKPF as H ON (A.BUKRS = H.BUKRS AND A.BELNR = H.BELNR AND A.GJAHR = H.GJAHR)
INNER JOIN VBRK as B ON (H.AWKEY = B.VBELN AND H.AWTYP = 'VBRK')
WHERE A.AUGDT >= $StartDate AND A.AUGDT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND A.AUGBL <> ''
// Generate two records from this source
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Payment Applied To Invoice',
EventTime: A.AUGDT, // Clearing Date
UserName: H.USNAM, // User from header of original invoice doc
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
UNION WITH {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Cleared',
EventTime: A.AUGDT, // Clearing Date
UserName: H.USNAM,
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Source 13: Invoice Written Off ==
// Tables: BSEG (for the invoice line) and BKPF (for clearing doc type)
DATA_SOURCE written_off FROM BSEG as A
INNER JOIN BKPF as H ON (A.BUKRS = H.BUKRS AND A.BELNR = H.BELNR AND A.GJAHR = H.GJAHR)
INNER JOIN VBRK as B ON (H.AWKEY = B.VBELN AND H.AWTYP = 'VBRK')
INNER JOIN BKPF as C ON (A.AUGBL = C.BELNR AND A.BUKRS = C.BUKRS AND A.AUGGJ = C.GJAHR)
WHERE A.AUGDT >= $StartDate AND A.AUGDT <= $EndDate
AND A.BUKRS IN ($CompanyCodes)
AND C.BLART = '[Your Write-Off Document Type]' // e.g., 'AB'
MAP {
InvoiceNumber: B.VBELN,
ActivityName: 'Invoice Written Off',
EventTime: A.AUGDT,
UserName: C.USNAM, // User who posted the write-off
BillingDocumentType: B.FKART,
CustomerNumber: B.KUNAG,
CompanyCode: A.BUKRS,
TotalInvoiceAmount: B.NETWR
}
// == Final Union of all sources ==
OUTPUT generated_invoices
UNION ALL posted_invoices
UNION ALL parked_invoices
UNION ALL approved_invoices
UNION ALL sent_invoices
UNION ALL corrected_invoices
UNION ALL due_invoices
UNION ALL reminders
UNION ALL disputes
UNION ALL payments
UNION ALL cleared_items
UNION ALL written_off