您的订单到收款:开票与发票处理数据模板
您的订单到收款:开票与发票处理数据模板
- 全面分析建议使用的属性
- 需要跟踪的关键流程步骤和里程碑
- SAP ECC数据提取实用指南
订单到收款:开票与发票处理属性
| 名称 | 说明 | ||
|---|---|---|---|
| 发票编号 InvoiceNumber | 开票凭证的唯一标识,也是开票流程的主要案例ID。 | ||
| 说明 发票编号在SAP中称为开票凭证编号,可唯一标识每张发票。在流程挖掘中,它充当案例ID,将创建、过账、发送、付款和清账等相关活动归为同一个端到端流程实例。 按发票编号分析流程,可以完整了解每笔开票交易从发起到最终结清的全过程。这对于计算应收账款周转天数(DSO)和发票整体周期时间等关键绩效指标至关重要,也为衡量和改进绩效提供了清晰依据。 重要性 这是跟踪发票全流程的关键标识,可用于分析每笔开票交易的周期时间、瓶颈和差异。 获取途径 SAP ECC表:VBRK,字段:VBELN 示例 90001234900012359000123690001237 | |||
| 开始时间 EventTime | 表示特定活动或事件发生时间的时间戳。 | ||
| 说明 事件时间记录发票生命周期中每项活动发生的准确日期和时间。它是流程挖掘中所有时间分析的基础,包括计算周期时间、识别瓶颈,以及监控流程绩效是否达到服务级别协议要求。 此属性通常由多个SAP表中的日期字段(如过账日期BUDAT)和时间字段(UZEIT)组合而成,这些表记录了变更或单据创建信息。准确的时间戳对于构建可靠的事件日志、确保绩效分析有效至关重要。 重要性 此属性是所有绩效分析的基础,可用于计算周期时间、持续时间以及流程步骤之间的等待时间。 获取途径 由多个表中的日期和时间字段构成,例如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 | |||
| 开票凭证类型 BillingDocumentType | 用于区分开票凭证类型的代码,例如发票、贷项凭证或借项凭证。 | ||
| 说明 开票凭证类型根据业务用途对交易进行分类。例如,“F2”表示标准客户发票,“G2”表示贷项凭证。SAP中配置了此分类,用于控制不同开票凭证的处理方式。 在流程挖掘中,此属性对于筛选和比较不同开票场景至关重要。分析人员可以分别查看标准发票和贷项凭证的流程,了解各自的路径、周期时间和难点,从而有针对性地改进流程。 重要性 可按不同开票流程进行分类和分析,例如比较标准发票与贷项凭证,因为两者的流程路径往往差异很大。 获取途径 SAP ECC表:VBRK,字段:FKART 示例 F2G2L2IV | |||
| 用户名 UserName | 执行活动或创建单据的用户ID。 | ||
| 说明 此属性记录负责某项事件的SAP用户ID,例如创建发票或过账付款的用户。它是分析流程中人为因素的重要依据。 借助这些数据,可以调查不同用户或团队之间的绩效差异、识别培训需求,并发现潜在的合规问题。该属性还可用于区分人工用户执行的手动活动与系统用户或批处理用户执行的自动化步骤,这对于计算自动化率至关重要。 重要性 可用于分析用户绩效和工作量分布,并区分手动与自动化活动,为自动化和效率提升举措提供支持。 获取途径 SAP ECC表:VBRK,字段:ERNAM(创建者);或BKPF,字段:USNAM(用户名);或CDHDR,字段:USERNAME(用户)。 示例 JSMITHBW_BATCHLROSSIMKUMAR | |||
| 事务代码 TransactionCode | 用于执行某项活动的SAP事务代码。 | ||
| 说明 事务代码(T-Code)是SAP中特定功能或程序的唯一标识,例如用于创建开票凭证的“VF01”。记录每个事件对应的T-Code,可以从技术和系统层面了解流程的执行方式。 这些信息对于根因分析很有价值。例如,若错误频繁发生,分析人员可以检查是否使用了非标准事务代码。它还有助于推导活动名称,并了解流程中使用了哪些系统功能。 重要性 提供活动执行方式的技术背景,便于分析流程偏差的根因,并识别非标准用户操作。 获取途径 SAP ECC表:CDHDR,字段:TCODE 示例 VF01VF02FB01F-28 | |||
| 付款条款 PaymentTerms | 卖方完成销售所依据的条件,包括付款安排。 | ||
| 说明 付款条款规定付款时间,例如“净30天”或“净60天”。这些条款由客户协商确定,是影响现金流的重要因素。 按付款条款分析流程,可以发现某些条款是否与较长的付款周期或较高的逾期付款率相关。这些信息有助于企业与客户协商更有利的条款,或调整财务计划。付款条款也是计算发票到期日的重要依据。 重要性 根据协商条款分析客户付款行为及其对现金流的影响,为优化商业协议提供参考。 获取途径 SAP ECC表:VBRK,字段:ZTERM 示例 Z030Z060Z001 | |||
| 最近数据更新时间 LastDataUpdate | 源系统最近一次数据刷新或提取的时间戳。 | ||
| 说明 此属性表示数据集最近一次从源系统更新的时间,为分析提供重要背景,帮助用户了解当前查看的数据是否为最新。 在仪表板和报告中,该时间戳可让相关人员了解数据的时效性,并合理预期近期交易的可见情况。通常在数据提取完成时生成。 重要性 让用户了解数据的时效性,这对于依据分析结果做出运营决策至关重要。 获取途径 在数据提取、转换和加载(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 | 客户应付款的截止日期。 | ||
| 说明 发票到期日是付款条款规定的付款截止日期,是管理应收账款和启动催收活动的重要依据。 将此属性与实际付款日期进行比较,可计算按时付款率这一关键绩效指标。按到期日分析发票,有助于预测现金流,并优先处理即将到期或已逾期的款项。该日期通常根据基准日期和付款条款推算。 重要性 这是衡量按时付款表现的基准,也是管理应收账款和预测现金流的重要依据。 获取途径 根据基准日期(BSEG-ZFBDT)和付款条款(BSEG-ZTERM)计算,并非总是存储在单独字段中。 示例 2023-05-152023-05-302023-06-20 | |||
| 币种 Currency | 发票金额所用的币种代码。 | ||
| 说明 此属性表示交易币种,例如USD、EUR或JPY,为发票总金额等货币数值提供必要背景。 分析跨国组织的数据时,币种字段对于正确解读和换算财务数据至关重要。它有助于统一报告,并确保金额在正确换算币种后再汇总,避免财务分析出现错误。 重要性 为所有货币数值提供必要背景,确保财务分析准确,尤其适用于多币种环境。 获取途径 SAP ECC表:VBRK,字段:WAERK 示例 USDEURGBPJPY | |||
| 是否自动化 IsAutomated | 用于标记活动是否由系统用户或自动化方式执行。 | ||
| 说明 此计算属性是一个布尔标记,用于区分手动活动和自动化活动。通常通过检查用户名是否属于已知系统用户或批处理用户列表来推导,例如“BATCHUSER”或“SAPSYSTEM”。 此标记对于衡量开票流程的自动化程度至关重要。许多组织都希望借此提升效率、降低成本。自动开票率这一关键绩效指标直接根据此属性计算,可用于跟踪自动化举措的进展。 重要性 可直接用于计算自动开票率,帮助衡量流程效率并跟踪自动化项目的成效。 获取途径 根据用户名属性推导。逻辑示例:IF UserName IN ('BATCH', 'SYSTEM', 'RFCUSER') THEN true ELSE false。 示例 truefalse | |||
| 是否返工 IsRework | 用于标记活动是否属于返工或更正步骤。 | ||
| 说明 此计算属性用于识别代表返工的活动,例如“发票已更正”或单据冲销。通常根据活动名称或与更正、取消相关的事务代码推导为布尔标记,例如用于取消开票凭证的“VF11”。 在流程挖掘中,此标记对于量化开票流程中的返工非常有用。它可直接支持发票更正率等关键绩效指标,并在流程图中呈现返工循环,突出显示会增加运营成本、延迟付款的低效环节和质量问题。 重要性 通过显示纠错所耗费的工作量,帮助量化流程低效和质量问题,并直接支持返工相关指标。 获取途径 根据活动名称或事务代码推导。例如:IF ActivityName = 'Invoice Corrected' OR TransactionCode = 'VF11' THEN true ELSE false。 示例 truefalse | |||
| 清账日期 ClearingDate | 收到付款并从应收账款中清除发票的日期。 | ||
| 说明 清账日期是发票等未清项目在财务系统中标记为已付款或“已清账”的日期,表示款项已收回并完成对账。 这是订单到收款周期中最重要的日期之一,可作为计算应收账款周转天数(DSO)和发票到收款整体周期时间的终点。分析清账日期有助于衡量收款流程的成效。 重要性 标记发票生命周期的最后一步,是计算DSO和整体周期时间的结束日期,也反映了收款效率。 获取途径 SAP ECC表:BSAD,字段:AUGDT 示例 2023-05-142023-06-012023-06-25 | |||
| 源系统 SourceSystem | 标识数据提取自哪个源系统。 | ||
| 说明 此属性用于标识数据的来源系统。在拥有多个ERP实例或集成系统的企业环境中,该字段有助于区分不同来源的数据。 在流程挖掘中,它对于数据验证以及跨系统或组织单元比较流程至关重要。通常在数据提取时填入固定值,用于标记数据集。 重要性 说明数据来源。在多系统环境中,这对于确保数据完整性和开展系统专项分析至关重要。 获取途径 通常在数据提取、转换和加载(ETL)过程中添加固定值,用于标识具体的SAP ECC实例(例如“ECC_PROD_NA”)。 示例 SAP_ECC_PRODECC_EU_100SAP_US_FIN | |||
| 过账日期 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)中与发票对应的输出类型的处理日期和时间推断。 采集 根据NAST表中处理状态为“1”(处理成功)的记录推断。 事件类型 inferred | |||
| 发票已结清 | 表示已成功付款发票的最终状态,即未结项目已通过相应付款或贷项凭证结清。此时发票视为已全部结清。 | ||
| 重要性 标志着该发票的订单到收款周期已成功完成。这是衡量平均发票周期时间的主要结束事件。 获取途径 当BSEG表中发票行项目的清账凭证(AUGBL)和清账日期(AUGDT)字段均已填入时,即表示发生此事件。 采集 事件发生时间为BSEG表中发票行项目记录的清账日期(AUGDT)。 事件类型 explicit | |||
| 发票已过账 | 发票已正式记入应收账款明细账和总账。此事件使发票具有法律效力,并反映客户所欠款项。 | ||
| 重要性 这是正式启动催收计时的重要节点。从发票生成到过账之间的时间,可揭示影响现金流的内部处理延迟。 获取途径 记录在BKPF表中。凭证编号(BELNR)的过账日期(BUDAT)标记此事件。对于暂存凭证,此事件发生在凭证转为已过账状态时。 采集 取自BKPF表中发票凭证的过账日期(BUDAT)。 事件类型 explicit | |||
| 已收到客户付款 | 已收到客户付款,并作为现金收款或银行存款记入系统。这会生成单独的付款凭证,但款项尚未核销到具体发票。 | ||
| 重要性 这是现金转换周期中的重要节点。从发送发票到收到付款的时间,是应收账款周转天数(DSO)的主要组成部分。 获取途径 通常以新凭证形式记录在BKPF和BSEG中,凭证类型表明这是客户付款,例如“DZ”。过账日期(BUDAT)标记此事件。 采集 取自BKPF中客户付款凭证的过账日期。 事件类型 explicit | |||
| 已生成发票 | 表示系统中已创建账单凭证。当会计凭证抬头表(BKPF)中新增特定发票凭证类型的记录时,即可捕获此事件。 | ||
| 重要性 这是整个开票流程的起点。分析此事件发生后的时间,可衡量发票创建周期时间,也是计算应收账款周转天数(DSO)的基础。 获取途径 记录在BKPF表中。特定凭证编号(BELNR)的创建日期(CPUDT)和时间(CPUTM)标记此事件。凭证类型(BLART)用于识别发票。 采集 取自BKPF表中发票凭证的创建时间戳(CPUDT)。 事件类型 explicit | |||
| 付款已核销到发票 | 收到的客户付款已与具体未结发票匹配并完成核销,该项目因此标记为已清账。这一对账步骤将付款与欠款关联起来。 | ||
| 重要性 此活动对于衡量收款核销周期时间至关重要。收款核销延迟会导致应收账款状态失真,也会掩盖可用现金。 获取途径 可根据清账事务推断,例如F-32。该事务会填充发票行项目中的清账字段,事件时间戳为清账日期。 采集 根据发票行项目表(BSEG)中已填入清账日期(AUGDT)推断。 事件类型 inferred | |||
| 发票已批准 | 表示发票已正式获批,可以过账或发送给客户。通常可根据暂存凭证转为已过账凭证这一变化推断此事件。 | ||
| 重要性 用于跟踪内部审批工作流,该环节常常存在瓶颈。分析此活动有助于支持“发票审批流程分析”仪表板,找出审批缓慢的人员。 获取途径 可根据凭证从暂存状态(VBKPF)转为已过账状态(BKPF)推断。若使用工作流系统,也可能在工作流日志中记录为明确事件。 采集 比较暂存凭证的创建日期(VBKPF)与最终凭证的过账日期(BKPF)。 事件类型 inferred | |||
| 发票已暂存 | 发票凭证已保存为初步状态,但尚未过账到总账。信息不完整或需要审核后再正式过账时,通常会采用这种方式。 | ||
| 重要性 用于跟踪过账前的步骤和潜在延误。凭证处于暂存状态的时间过长,可能表明数据质量存在问题,或预审批流程中存在瓶颈。 获取途径 暂存凭证存储在VBKPF表中。此处创建、之后再过账的凭证即表示发生了此活动。 采集 通过FV70等事务保存暂存凭证时记录。 事件类型 explicit | |||
| 发票已更正 | 表示发生了返工:初始发票被发现有误,随后被冲销。可通过识别与原发票关联的冲销凭证来捕获此事件。 | ||
| 重要性 此事件反映流程低效和质量问题。更正频繁发生,说明上游销售或开票数据可能存在问题,有助于支持“发票返工与错误率”仪表板。 获取途径 查找BKPF-STBLG指向原凭证的冲销凭证即可识别此事件。创建该冲销凭证时,即表示事件发生。 采集 创建冲销凭证时记录,例如通过FB08创建。 事件类型 explicit | |||
| 发票已核销 | 这是一种替代性的最终状态,表示发票已被认定无法收回,未收金额已转入坏账科目。发票由此结清,但未收到客户付款。 | ||
| 重要性 这代表负面的流程结果和收入损失。跟踪此类事件有助于分析坏账原因并改进信用管理政策。 获取途径 通过分析发票的清账交易推断。如果清账凭证过账到指定的坏账费用总账科目,则视为发票已核销。 采集 当清账交易涉及过账到指定的坏账总账科目时,即可推断。 事件类型 inferred | |||
| 已创建争议案件 | 已针对发票登记正式争议,通常由客户投诉引起。此记录保存在SAP争议管理系统中。 | ||
| 重要性 可识别付款可能延迟的发票,并突出显示导致客户不满的潜在问题。这标志着重要的例外处理流程开始。 获取途径 从争议案件表(UDM_CASE)中与发票会计凭证关联的案件创建记录中捕获。 采集 用户通过事务代码UDM_DISPUTE创建争议案件时记录。 事件类型 explicit | |||
| 已到发票付款到期日 | 这是一个计算得出的事件,标记根据付款条款应付发票款项的日期。它并非用户或系统执行的活动,而是一个重要时间点。 | ||
| 重要性 此事件对于分析付款行为和合规情况至关重要。它是判断是否按时付款以及计算按时付款率KPI的基准。 获取途径 将当前日期与净到期日进行比较即可得出。到期日可从字段BSEG-ZFBDT获取,也可根据基准日期和付款条款计算。 采集 将系统日期与发票行项目(BSEG)中的净到期日字段进行比较。 事件类型 calculated | |||
| 已发送付款提醒 | 系统已针对逾期发票生成并向客户发送催款通知或付款提醒。可从催款历史日志中捕获此事件。 | ||
| 重要性 有助于评估催收策略的效果。分析从发送提醒到收到付款的时间,是衡量付款提醒效果KPI的关键。 获取途径 记录在催款数据表中,具体包括MHNK(催款数据抬头)和MHND(催款数据行项目)。这些记录由催款运行(事务代码F150)生成。 采集 针对逾期项目执行催款运行(F150)时记录。 事件类型 explicit | |||
数据提取指南
步骤
- 进入ABAP编辑器:登录SAP ECC系统。使用事务代码
SE38进入ABAP编辑器。 - 创建程序:在“程序”字段中输入新程序名称,例如
Z_PM_O2C_INVOICE_EXTRACT,然后点击“创建”按钮。填写描述性标题,并将程序类型设为“可执行程序”。 - 定义选择屏幕:在程序源代码中定义选择屏幕参数,以便用户筛选要提取的数据。关键参数包括凭证创建日期范围(
S_ERDAT)、公司代码(S_BUKRS)和开票凭证类型(S_VBTYP)。 - 定义数据结构:声明一个内部表结构,用于存放最终的事件日志数据。该结构必须包含
InvoiceNumber、ActivityName、EventTime等字段,以及UserName、BillingDocumentType、CustomerNumber、CompanyCode和TotalInvoiceAmount等建议属性。 - 编写数据筛选逻辑:编写核心ABAP逻辑以筛选数据。首先,根据用户在选择屏幕中输入的条件,从
VBRK和BKPF表中选取主要开票凭证,并存入临时内部表。 - 提取活动:遍历初始开票凭证列表。针对每个凭证,从不同表中继续查询,以识别所需的13项活动。例如,查询
NAST表获取“已向客户发送发票”事件,查询BSEG表获取清账信息(“发票已清账”“已核销付款”),查询MHNK表获取催款数据(“已发送付款提醒”)。 - 生成事件日志表:针对上一步找到的每项活动,在最终事件日志内部表中新增一条记录。确保
InvoiceNumber、ActivityName、EventTime及其他属性均正确映射自源表。 - 写入应用服务器:循环结束且事件日志内部表填充完毕后,使用
OPEN DATASET、LOOP AT... TRANSFER和CLOSE DATASET语句,将内部表内容写入SAP应用服务器上的文本文件。请指定可访问的逻辑文件路径。 - 获取文件:使用事务代码
AL11浏览应用服务器目录并找到生成的文件。联系SAP Basis团队,将文件从服务器下载到本地计算机或共享网络位置。 - 最终格式检查:打开下载的文件,确认其为带标题行的逗号分隔值(CSV)文件。请使用UTF-8编码保存,以确保ProcessMind可以上传该文件。
配置
- 前提条件:具备创建和执行ABAP程序的权限(事务代码SE38)。具备读取FI和SD表的权限,包括
VBRK、VBRP、BKPF、BSEG、NAST、MHNK和UDM_CASE_ATTR00(用于争议管理)。 - 日期范围选择:程序应设置必填的日期范围参数,通常依据凭证创建日期(
VBRK/BKPF中的ERDAT)。首次提取建议选择3至6个月的数据,以控制数据集规模。 - 关键筛选条件:始终按公司代码(
BUKRS)筛选,以限定提取范围。强烈建议按开票凭证类型(VBRK中的VBTYP)或会计凭证类型(BKPF中的BLART)筛选,只纳入相关发票类型,例如标准会计发票“RV”,并排除贷项通知单等其他凭证。 - 性能注意事项:如果数据集覆盖数月以上且规模较大,应将程序作为后台作业运行,以避免会话超时。ABAP逻辑应使用索引表读取进行优化,并避免在嵌套循环中执行数据库查询。建议先将数据读入内部表,再进行处理。
- 输出文件配置:ABAP代码必须指定应用服务器上的输出文件路径,以及CSV文件的分隔符,通常为逗号或分号。请确保该路径是全局配置且可访问的目录。
查询示例 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等表。此类权限通常仅授予系统管理员或特定数据分析团队。 - 连接数据库:使用DBeaver、Oracle SQL Developer或Microsoft SQL Server Management Studio等标准SQL客户端连接SAP ECC数据库。
- 准备SQL查询:将“query”部分提供的完整SQL查询复制到SQL客户端的编辑器中。
- 替换占位符:查询中包含多个占位符,需替换为适用于您环境的值,包括:
'YYYYMMDD':将所有实例替换为所需分析期间的起止日期。请务必将数据筛选在合理的时间范围内。'XXXX':替换为您要分析的具体公司代码。[Your Invoice Output Type]:填写用于向客户发送发票的输出类型代码,例如“RD00”。[Your Bad Debt G/L Account]:填写用于核销无法收回发票的总账科目编号。[Your Dispute Case Invoice Attribute]:填写争议管理配置中用于存储发票编号的属性名称,例如“INVOICE_ID”。
- 检查时间戳函数:查询使用通用的
CAST(CONCAT(date_field, time_field) AS TIMESTAMP)语法。您可能需要根据具体数据库系统进行调整,例如Oracle使用TO_TIMESTAMP,SQL Server使用DATETIMEFROMPARTS。 - 执行查询:运行修改后的查询。所需时间取决于SAP表的规模和所选日期范围,可能较长。
- 检查结果:查询完成后,检查输出是否包含预期列:InvoiceNumber、ActivityName、EventTime及建议属性。确认没有错误或空结果。
- 导出为CSV:通过SQL客户端将完整结果集导出为CSV文件。请使用UTF-8编码,避免特殊字符显示异常。
- 准备上传:上传到流程挖掘工具前,确认CSV列标题与所需属性名称完全一致,例如
InvoiceNumber、ActivityName、EventTime和UserName。
配置
- 数据库连接:需要直接以只读方式连接底层SAP ECC数据库。此方法完全绕过SAP应用层。
- 授权:数据库用户必须对查询中涉及的所有表拥有
SELECT权限,这些表涉及FI、SD以及可能的FSCM模块。 - 日期范围:必须按具体日期范围筛选查询,以确保性能和数据量合理。建议从3至6个月的数据开始。查询中多个位置的日期筛选占位符
'YYYYMMDD'都必须设置。 - 公司代码筛选:查询设计为按公司代码(
BUKRS)筛选。通常建议每次分析一个或少数几个公司代码。 - 凭证类型配置:识别发票更正、核销或已发送凭证等事件的逻辑,取决于SAP标准配置。如果贵组织使用自定义凭证类型(
BLART)、输出类型(KSCHL)或相关流程的总账科目,可能需要调整查询。 - 性能注意事项:在运行中的SAP生产系统上执行此查询可能消耗大量资源并影响运营性能。强烈建议在非高峰时段执行大型数据提取,或使用专用数据库报表副本。
查询示例 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工具许可证,例如Informatica PowerCenter with SAP Connector或Talend with SAP Connector。确认您拥有SAP用户凭据及必要授权,可以读取所需的财务、销售和系统表(
BKPF、BSEG、VBRK、NAST、MHNK、UDM_CASE_ATTR00、CDHDR、CDPOS)。 - 建立SAP连接:在ETL工具中新建与SAP ECC系统的连接。配置应用服务器、系统编号、客户端、用户和密码等连接信息,并测试连接是否成功。
- 定义数据源:针对每项要提取的活动,在ETL作业中将对应的SAP表定义为数据源。例如,添加
VBRK以提取发票生成数据,添加BKPF以提取过账事件,添加NAST以提取客户沟通记录。 - 为各项活动构建提取逻辑:为所需的13项活动分别创建数据流或转换。在每个数据流中添加筛选条件,选取相关记录。例如,按公司代码(
BUKRS)、凭证类型(BLART)和具体日期范围(如创建日期ERDAT)筛选。 - 映射字段并转换数据:在每个数据流中,将SAP源表字段映射到目标事件日志结构:InvoiceNumber、ActivityName、EventTime、UserName及其他建议属性。使用转换逻辑为每个数据流设置对应的“ActivityName”,并正确格式化日期和时间戳。
- 处理复杂活动:对于“发票到期日已到”等计算事件,可使用基准付款日期(ZFBDT)和付款条件逻辑计算到期日,或直接从BSEG读取净到期日(NETDT)。对于根据更改日志推导的事件(如“发票已批准”),可能需要根据凭证编号和日期联接BKPF与CDHDR/CDPOS等表。
- 合并活动数据:在ETL工具中使用“Union”或“Merge”转换,将13个独立数据流的输出合并为一个数据集。合并前请确保所有数据流的列名和数据类型一致。
- 配置目标位置:定义事件日志的最终输出位置,可以是文本文件(CSV)、数据库表或暂存区的直接连接。
- 设置提取计划:配置提取的日期范围参数。首次加载可提取6至12个月的数据;后续增量加载则可设置为从上次运行日期开始提取。
- 执行并导出:运行ETL作业。完成后检查输出文件,确认格式符合要求。最终输出应为单个CSV文件,每行代表一个唯一事件,可直接上传到ProcessMind。
配置
- SAP连接:需要连接目标SAP ECC系统的应用服务器。SAP用户必须拥有RFC访问权限,以及查询中指定的
VBRK、BKPF、BSEG、NAST等表的授权。 - ETL工具许可证:必须拥有商业ETL工具及其专用SAP连接器的有效许可证。
- 日期范围:建议提取3至6个月的数据,以获得具有代表性的分析样本,同时避免给系统造成过大负载。请使用可配置参数设置起止日期。
- 关键筛选条件:始终按公司代码(
BUKRS)筛选,以限定提取范围。还必须按相关开票凭证类型(VBRK-FKART)和会计凭证类型(BKPF-BLART)筛选,仅纳入标准发票,并排除贷项通知单或内部凭证等其他类型。 - 性能:从
BSEG等大型表提取数据可能较慢。请使用精确筛选条件,避免提取不必要的字段,并安排在非高峰时段执行,以尽量减少对SAP源系统性能的影响。
查询示例 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 加快现金回笼:立即优化开票与发票处理!
消除低效环节,将周期时间缩短30%,改善现金流。
无需信用卡,几分钟即可开始优化。