数据模板:订单到收款(O2C)- 销售订单处理
订单到收款:销售订单处理数据模板
- 建议收集的属性
- 需要追踪的关键活动
- SAP ECC数据提取指南
从订单到收款——销售订单处理属性
| 名称 | 描述 | ||
|---|---|---|---|
销售订单 SalesOrder | 销售订单单据的唯一标识,用作跟踪整个订单到收款流程的主案例。 | ||
描述 销售订单是销售流程的核心单据,代表客户对商品或服务的需求,包含从启动到完成所需的全部信息。 在流程挖掘中,此属性用作Case ID(案例标识)。每个唯一的销售订单号代表一个端到端的流程实例。按销售订单分析,有助于跟踪完整生命周期、衡量周期时间,并识别各个客户订单的差异。 为何重要 它是串联所有相关活动和事件的关键,让每笔客户订单的旅程都能被端到端完整分析。 获取方式 位于销售单据抬头数据表(VBAK)的VBELN字段。 示例 900001234590000123469000012347 | |||
最后数据更新 LastDataUpdate | 指示该记录上次从源系统刷新时间的时间戳。 | ||
描述 该属性记录某个事件或流程实例最近一次数据提取或更新的日期和时间,用于说明所分析数据的时效性。 在仪表板和报表中,这一信息至关重要,能帮助用户判断洞察是否及时。它可确认分析结果反映的是最新运营状态,还是基于较早的数据,从而合理管理用户对数据时效性的预期。 为何重要 让用户清楚数据新鲜度,这对基于流程挖掘做出及时且明智的决策至关重要。 获取方式 这是在数据导入时由数据抽取工具或流程写入的元数据属性,不会存储在源SAP表中。 示例 2024-06-10T05:00:00Z2024-06-11T05:00:00Z2024-06-12T05:00:00Z | |||
开始时间 StartTime | 指示某项活动或事件开始时间的时间戳。 | ||
描述 开始时间,也称事件时间戳,记录特定活动发生的精确日期和时间。例如,它会记录创建销售订单、发货过账或发票过账的时间点。 该时间戳是流程挖掘中所有基于时间分析的基础。它用于计算活动之间的周期时间、衡量单个流程实例的总耗时,并识别延迟或瓶颈。准确的时间戳对绩效分析仪表板至关重要,例如用于监控准时交付或履约周期的仪表板。 为何重要 这是计算各类绩效指标(如周期时间与持续时长)的关键属性,对识别流程瓶颈至关重要。 获取方式 这是一个复合属性,通常在数据抽取时将日期字段(如ERDAT)与时间字段(如ERZET)合并获得,来源包括VBAK(Sales Order)、LIKP(Delivery)和VBRK(Invoice)等SAP表。 示例 2023-04-15T09:00:12Z2023-04-16T14:30:00Z2023-04-20T11:22:45Z | |||
活动 Activity | 销售订单流程中某个业务步骤或事件的名称。 | ||
描述 此属性描述订单到收款流程中的单一步骤,例如“创建销售订单”“创建交货”或“收到付款”。这些活动是为每个销售订单重建流程路径的基石。 分析这些活动的先后顺序与时间间隔是流程挖掘的核心。它有助于可视化流程图、识别瓶颈、发现流程变体,并对照标准模型进行合规性检查。活动通常由单据创建事件、状态变更或系统记录的特定事务码综合推断而来。 为何重要 活动是流程图的骨架,便于可视化与分析流程走向、偏差与瓶颈。 获取方式 这是一个派生属性,通常在数据抽取时将SAP事务码(T-Codes)、单据状态变更(如来自VBUK、VBUP表)或变更日志(CDHDR、CDPOS)映射为易于理解的活动名称。 示例 销售订单已创建已创建交货单货物已出库发票已创建已收款 | |||
源系统 SourceSystem | 标识数据的来源系统。 | ||
描述 该属性标识数据来源系统,例如某个SAP ECC实例名称或客户端编号。在存在多个生产系统或包含遗留系统数据的环境中,它为数据提供必要的上下文。 分析时可据此按来源筛选或分组数据,尤适用于跨系统流程对比,或在系统迁移项目中确保数据一致性与完整性。 为何重要 提供关键业务上下文,在多系统环境下尤为重要,便于横向对比流程,并确保数据血缘清晰可追溯。 获取方式 该值通常在数据抽取过程中添加,往往是表示SAP系统ID(SAPSID)或客户端(MANDT)的静态值。 示例 ECC_PROD_800SAP_ERP_EU1ECC_QAS_300 | |||
交货阻止 DeliveryBlock | 用于表示销售订单是否处于发运阻断状态、从而禁止创建交货单的代码。 | ||
描述 交货阻止是设置在销售订单(抬头或行项目级别)上的一种状态,用于在交货步骤前暂时中止流程。该阻止可由用户手动设置,也可因信用额度不足、数据不完整等原因由系统自动触发。 此属性对“销售订单阻止与返工分析”仪表板至关重要。分析交货阻止的发生频次、持续时间及原因,有助于识别履约流程中的主要瓶颈。减少此类阻止,是提升准时交付与整体周期时间的关键。 为何重要 可直接定位履约流程中的瓶颈。分析订单被阻止的原因与频率,是提升流程效率的关键。 获取方式 位于销售单据抬头数据表(VBAK)的LIFSK字段。 示例 0102Z1 | |||
净额 NetAmount | 销售订单的总金额,不含抬头层的税费和折扣。 | ||
描述 净额表示该销售订单的金额,是与每个流程实例关联的关键财务指标。 此属性是价值导向流程挖掘的基础。它可帮助优先关注高金额订单,聚焦推进改进。分析人员可以将延误、返工等流程问题与财务影响关联起来,为变革建立更有力的商业论证。例如,可用于分析高金额订单相较低金额订单的处理效率是更高还是更低。 为何重要 支持基于价值的分析,优先将改进投入到对公司财务影响最大的订单。 获取方式 位于销售单据抬头数据表(VBAK)的NETWR字段。 示例 1500.0012550.75850.50 | |||
客户编号 CustomerNumber | 下达销售订单的客户唯一标识。 | ||
描述 该属性表示“售达方”,即与销售订单关联的客户编号,用于将交易与主数据中的特定客户对应。 按客户编号分析可对流程进行细分,从客户维度了解行为与绩效。例如识别哪些客户的周期时间最长、返工率最高或订单变更最频繁。这对提升客户关系管理与服务水平至关重要。 为何重要 支持以客户为中心的分析,帮助识别影响特定客户的流程问题,并衡量客户层面的绩效。 获取方式 位于销售单据抬头数据表(VBAK)的KUNNR字段。 示例 100234100567200112 | |||
拒绝原因 RejectionReason | 用于说明销售订单行被拒绝或取消原因的代码。 | ||
描述 拒绝原因用于说明为何销售订单或某个行项目未能履行,可能由于客户取消、无货可供或其他业务原因。 此属性是“销售订单取消趋势”仪表板的关键。通过分析最常见的拒绝原因,企业可以识别丢单的根本原因,并据此改进库存管理、定价策略或客户沟通,从而降低订单取消率。 为何重要 揭示订单取消背后的原因,支持根因分析,从而减少流失销售并提升预测准确性。 获取方式 位于销售单据项目数据表(VBAP)的ABGRU字段。 示例 0215Z5 | |||
物料号 MaterialNumber | 所售产品或服务的唯一标识。 | ||
描述 物料编码用于识别销售订单行中的具体物料。由于单个销售订单可包含多个物料,此属性通常在行项目级进行分析。 按物料编码分析流程有助于发现产品层面的问题。它可以揭示某些产品是否对应更长的履约时间、更高的交货阻止率,或更频繁的发票差异。这对供应链和产品管理优化各产品线流程至关重要。 为何重要 支持按产品维度进行流程分析,识别哪些产品与延误、拦截或返工等低效相关。 获取方式 位于销售单据项目数据表(VBAP)的MATNR字段。 示例 FG-1001-ARAW-205BSERV-INSTALL | |||
用户 User | 创建或最后更改该单据、或执行该活动的员工用户ID。 | ||
描述 此属性记录对流程中某一环节负责的SAP用户ID。例如,它可标识创建订单的销售文员或过账发货的仓库人员。 按用户分析有助于了解工作量分布、识别培训需求,并发现不同用户在执行同一任务时的差异。该属性对聚焦资源绩效、合规与识别人工干预的仪表板至关重要。 为何重要 助您洞察资源绩效与工作负载,并识别用户层面的流程偏差,是进行合规与自动化分析的关键基础。 获取方式 在多个SAP抬头表中作为创建者字段(ERNAM)或更改者字段(AENAM)出现,如VBAK、LIKP、VBRK。 示例 CBURKEJSMITHRWILLIAMS | |||
销售组织 SalesOrganization | 负责销售产品或服务的组织单元。 | ||
描述 在 SAP 中,销售组织是按销售需求划分公司的关键组织单元,负责谈判销售条件并分销商品和服务。 在流程挖掘中,该属性是重要的分析维度。它可用于对比不同销售单元、区域或事业部的流程绩效、效率与合规性,帮助识别高绩效组织的最佳实践,并找出其他组织的改进空间。 为何重要 支持组织对标,可在不同业务单元或地区对比流程效率与合规性。 获取方式 位于销售单据抬头数据表(VBAK)的VKORG字段。 示例 100025003100 | |||
销售订单周期时长 SalesOrderCycleTime | 从销售订单创建到最终关闭或收款的总耗时。 | ||
描述 该计算指标衡量单个销售订单的端到端处理时长,通常为首个活动(“Sales Order Created”)与最后一个活动(如“Payment Received”或“Order Item Closed”)的时间戳差值。 它是“销售订单端到端周期时间”仪表板及履约周期时间KPI的核心度量,可从全局反映流程效率,并用于识别长周期订单与整体流程健康状况。分析该指标的分布有助于设定基准并持续跟踪改进举措的成效。 为何重要 这是衡量整体流程速度与效率的核心KPI,为改进计划提供重要基线。 获取方式 这是基于事件日志计算得到的指标:对同一SalesOrder取StartTime的最大值与最小值之差。 示例 10天4小时25天11小时5天2小时 | |||
信用检查状态 CreditCheckStatus | 表示销售单据的信用检查状态。 | ||
描述 该属性展示对销售订单执行自动或人工信用检查后的结果,常见状态包括“通过”“拒绝”或“冻结”。 它是“信用检查处理时长分析”仪表板的关键属性。信用检查阶段的延迟或冻结会显著拉长整体履约周期。通过分析该状态,可评估信用管理流程的效率及其对销售速度的影响。 为何重要 直接影响订单处理速度。分析该状态可识别信用管理中的瓶颈,这些瓶颈会延误履约。 获取方式 信用状态字段可在销售单据抬头状态表(VBUK)或直接在VBAK中找到(如CMGST)。 示例 ABD | |||
是否准时交付 IsOnTimeDelivery | 用于标识货物是否在确认交货日期当日或之前发运的布尔标识。 | ||
描述 该计算属性用于比较销售订单的实际发货过账日期与“ConfirmedDeliveryDate”。若发货日期不晚于确认日期,则标记为true,否则为false。 借助此属性,可快速搭建“准时交付绩效”仪表板并计算准时交付率KPI;无需在每个分析或图表中临时比对日期,即可完成汇总与可视化,直观衡量交付可靠性。 为何重要 提供清晰易懂的交付绩效指标,便于计算整体准时交付率这一KPI。 获取方式 这是一个计算属性。其逻辑将“Goods Issued”活动的时间戳与“ConfirmedDeliveryDate”属性的取值进行比较。 示例 truefalse | |||
是否返工 IsRework | 用于标识销售订单在初次创建后是否发生过重大变更或返工的布尔标识。 | ||
描述 该计算属性用于识别发生过返工的流程实例,例如包含一次或多次“Sales Order Changed”活动。哪些变更视为返工(如价格、数量或交期调整)的具体规则将在项目启动阶段定义。 该属性是“销售订单返工与变更频率”仪表板及返工率KPI的关键支撑。它使分析更简化,可直接筛选并对比“直通式”订单与需要人工更改的订单,从而量化返工对周期时间与成本的影响。 为何重要 直接量化返工发生的频率,便于分析其成因及其对整体流程效率和周期时间的影响。 获取方式 这是基于事件日志计算得到的属性。其逻辑用于检测是否存在“Sales Order Changed”活动,或来自CDHDR/CDPOS表的特定变更事件。 示例 truefalse | |||
确认交货日期 ConfirmedDeliveryDate | 向客户确认货物或服务已交付的日期。 | ||
描述 这是基于物料可用性和排程向客户承诺的交付日期,是衡量交付表现的基线。 该属性是“准时交付表现”仪表板和准时交付率KPI的基础。通过将确认交付日期与实际“发货过账”日期对比,可判断订单是准时、提前还是延迟交付。这是衡量供应链可靠性与客户满意度的核心指标。 为何重要 这是衡量准时交付表现的基准,是影响客户满意度和供应链效率的关键KPI。 获取方式 位于销售单据计划行表(VBEP)的EDATU字段。 示例 2023-05-102023-06-202023-07-01 | |||
装运条件 ShippingConditions | 定义向客户交付货物的总体发运策略。 | ||
描述 装运条件决定订单的装运方式,例如“标准”“加急”或“自提”。该条件由客户与企业协商确定,并会影响物流计划。 该属性用于“装运方式效率与成本”分析。按装运条件对流程分段后,企业可以评估是否某些方式更易延迟或周期更长。基于这些数据,可优化物流并更好管理客户对交付时效的预期。 为何重要 支持分析物流绩效,判断特定配送方式是否与延迟或更高效率相关。 获取方式 位于销售单据抬头数据表(VBAK)的VSBED字段。 示例 011020 | |||
从订单到收款——销售订单处理活动
| 活动 | 描述 | ||
|---|---|---|---|
发票已创建 | 标记客户发票或开票凭证的创建。该显式事件会在系统中生成新凭证,启动流程中的付款环节。 | ||
为何重要 这是启动“开票到收款周期时间”计时的重要里程碑。开票延迟会直接影响现金流。 获取方式 在VBRK表(开票凭证:抬头数据)中依据创建日期(ERDAT)记录。与销售订单或交货的关联存于VBFA表。 捕获 基于VBRK表中创建时间戳(ERDAT)的事件。 事件类型 explicit | |||
已收款 | 该事件表示客户付款已到账并核销至对应发票,清除了未结的应收账款项目。它属于会计类事件,通常由财务凭证清账推断而来。 | ||
为何重要 这是实现销售回款的最后一步,也是衡量“开票到收款周期时长”和整体“销售订单履行周期时长”的终点。 获取方式 根据 BSEG 表中客户行项目的清账凭证信息推断。当 BSEG-AUGBL(清账凭证)与 BSEG-AUGDT(清账日期)已填写时,视为已收款。 捕获 当 BSEG 表中应收行项目的清账日期(AUGDT)被填写时推断。 事件类型 inferred | |||
订单已确认 | 该活动表示销售订单已通过所有初始检查并确认可履约。通常在订单不再被阻止且计划行存在已确认数量时即可判定。 | ||
为何重要 这是区分录单与履约的关键里程碑,也是衡量履约前置期和准时交付表现的起点。 获取方式 当VBEP中的计划行存在已确认数量(BMENG>0),且订单未被交货拦截(如VBUK-LIFSK为空)时,可据此推断。 捕获 当计划行已确认(VBEP-BMENG > 0),且抬头级拦截被解除时推断。 事件类型 inferred | |||
订单行关闭 | 该活动标记销售订单行项目的最终关闭,表示已全部交付、已开票并视为完成。此结论依据行项目的总体状态推断。 | ||
为何重要 作为流程的成功结束事件。分析行项目的关闭时间,有助于评估端到端时长,并识别不必要地长期保持打开状态的订单。 获取方式 依据 VBUP 表(销售凭证:项目状态)中的总体状态字段推断。当 VBUP-GBSTA 为“C”(完全处理)时,该行项目关闭。 捕获 当行项目状态(VBUP-GBSTA)变为“C”(完全处理)时推断。 事件类型 inferred | |||
货物已出库 | 关键事件:货权完成转移且货物正式出库。这会触发财务过账,生成物料凭证并更新库存。 | ||
为何重要 这是“发运”事件,是衡量准时交付和履行前置时间的关键里程碑。它会触发财务更新,在实物履行流程中一旦发生即不可逆转。 获取方式 创建带有发出货物移动类型(如601)的物料凭证(MKPF/MSEG),并与交货凭证关联。 捕获 创建带有发出货物移动类型的物料凭证(MKPF/MSEG),并与交货关联。 事件类型 explicit | |||
销售订单已创建 | 标记销售订单凭证的创建。用户通过 SAP 事务码 VA01 保存新订单时,会记录此显式事件。 | ||
为何重要 这是订单到收款(O2C)流程的主要起始事件。分析其发生时间对于衡量整体周期时长与接单速率至关重要。 获取方式 记录在VBAK表(销售凭证抬头数据)中,使用创建日期(ERDAT)和时间(ERZET)。事务代码记录在VBAK-TCODE。 捕获 基于VBAK表中的创建时间戳(ERDAT、ERZET)的事件。 事件类型 explicit | |||
交货签收已确认 | 该活动表示确认客户已收货。当系统记录交货证明时予以捕获,并且通常会更新交货单状态。 | ||
为何重要 该事件提供实际交货日期,是准确衡量相对于承诺日期的“准时交付率”的关键。 获取方式 当交货证明状态(VBUK-PODAT)被设为“C”(已确认)时推断。确认日期存于 VLPOD-PODAT。该功能不一定启用。 捕获 根据交货的 POD 状态更新(VBUK-PODAT)或 VLPOD 表记录来推断。 事件类型 inferred | |||
发票已取消 | 指对已创建的开票凭证进行冲销。这是一个显式交易,会生成新的冲销凭证以抵销原单。 | ||
为何重要 跟踪发票冲销有助于识别定价、发运差异或数据错误等问题,为“发票差异率”KPI提供支撑。 获取方式 当创建了取消开票凭证(VBRK-VBTYP='N'或'O')时,会记录一条明确事件;原始发票的引用在VBRK-SFAKN中。 捕获 在VBRK中创建取消凭证,并引用原始发票。 事件类型 explicit | |||
已创建交货单 | 该事件表示创建了外向交货单,这是通知仓库开始拣货与发运的指令。该事件直接来源于单据流。 | ||
为何重要 这是实物流履行的第一步。订单确认到创建交货单之间的时间,反映了物流流程启动的速度。 获取方式 在LIKP表(SD凭证:交货抬头数据)中创建记录。与销售订单的关联保存在单据流表VBFA中。 捕获 基于LIKP表的创建时间戳的事件,通过VBFA表关联。 事件类型 explicit | |||
已执行信用审核 | 表示该销售订单的客户已完成自动或手工的信用检查。通常可从单据整体信用状态的变化中推断。 | ||
为何重要 信用检查往往是关键瓶颈。衡量该步骤的耗时对于“信用检查处理时间分析”以及加速订单处理至关重要。 获取方式 依据 VBUK 表中的信用状态字段(销售凭证:抬头状态)推断。当 VBUK-CMGST 由“冻结”变为“放行”时标记该活动。 捕获 依据总体信用状态字段(VBUK-CMGST)的变更推断。 事件类型 inferred | |||
已设置交货阻止 | 指对销售订单施加交货阻塞,从而阻止创建交货单。该行为可从变更日志中直接获取,或从状态表中推断。 | ||
为何重要 此活动与“销售订单阻止率”KPI直接相关。识别阻止出现的原因与频次,有助于揭示履约延迟的原因。 获取方式 可在变更日志(CDHDR/CDPOS)中查找字段VBAK-LIFSK;或通过观察VBAK-LIFSK字段被填写的时点进行推断。 捕获 来自变更文档的事件,字段为VBAK-LIFSK或VBAP-LIFSP。 事件类型 explicit | |||
拣货完成 | 表示该交货的所有物料已在仓库完成实际拣配。若启用仓储管理(WM),可根据Transfer Order的状态进行推断。 | ||
为何重要 分析拣货用时有助于优化仓储作业;此处的延误会直接影响整体发运时效与履约周期。 获取方式 根据交货行项目在 LIPS-KOSTA 中的拣配状态变为“C”(已全部拣配)来推断。若启用 WM,也可依据传输订单确认(LTAK/LTAP 表)。 捕获 根据拣配状态(LIPS-KOSTA)的变更或 WM 传输订单确认来推断。 事件类型 inferred | |||
订单已取消 | 表示销售订单在履约前已被取消。通常通过在订单相关行项目上设置“拒绝原因”来体现。 | ||
为何重要 这是一个关键失败节点,直接支撑“订单取消率”KPI。了解订单取消的时间与原因,有助于洞察销售流程中的问题。 获取方式 当销售订单所有有效行的 VBAP-ABGRU(拒绝原因)被填写时推断。变更日期可在 CDHDR/CDPOS 中获取。 捕获 当所有行项目的“拒绝原因”字段(VBAP-ABGRU)被填写时推断。 事件类型 inferred | |||
销售订单已变更 | 指对已创建的销售订单所做的修改。当数量、价格或日期等字段被更改时,这些变更会记录在专用的变更日志表(CDHDR、CDPOS)中。 | ||
为何重要 跟踪变更有助于识别返工、流程不稳定以及数据质量问题。频繁变更往往意味着最初的订单录入存在问题,从而导致延误。 获取方式 从变更文档表CDHDR(抬头)与CDPOS(行项目)中获取,OBJECTCLAS='VERKBELEG'。可识别时间戳及被修改的字段。 捕获 来自变更文档表(CDHDR、CDPOS)的事件,针对销售单据对象。 事件类型 explicit | |||
提取指南
步骤
- 程序开发:通过事务码 SE38 或 SE80 新建一个可执行 ABAP 程序,用于实现完整的抽取逻辑。
- 定义选择屏幕:在程序中创建选择屏幕用于筛选数据,包含销售凭证创建日期(VBAK-ERDAT)、销售组织(VBAK-VKORG)和销售凭证类型(VBAK-AUART)等参数,便于复用和管理。
- 数据声明:定义用于承载各 SAP 表数据的内部表与结构(如 VBAK、VBAP、VBFA、CDHDR、CDPOS、VBRK、BSAD),并定义事件日志的最终输出结构,使之与所需属性一致。
- 选择基础销售订单:根据选择屏幕的输入编写初始 SELECT 语句,获取销售订单抬头(VBAK)与项目(VBAP),作为待分析的核心案例数据集。
- 抽取“创建”事件:循环处理选中的 VBAK 记录。为每条记录在事件日志中写入“销售订单已创建”活动,并使用 VBAK-ERDAT 与 VBAK-ERZET 作为 StartTime。
- 抽取变更日志事件:从 CDHDR 与 CDPOS 读取所选销售订单且 OBJECTCLAS 为 'VERKBELEG' 的记录。遍历结果识别具体字段变更,例如 VBAK-LIFSK 变更表示“设置发运阻断”,VBUK-CMGST 变更表示“已执行信用检查”。其他相关变更可统一记录为“销售订单已变更”。
- 抽取单据流数据:针对所选销售订单查询单据流表(VBFA)。该表将销售订单与后续单据(如交货、货物移动、发票)关联。选择所有相关单据以便后续处理。
- 抽取交货与履约相关事件:基于 VBFA 的交货单号,查询 LIKP 和 LIPS 获取“交货已创建”。查询 MKPF 与 MSEG(移动类型 '601')获取“货物已发出”。如启用仓库管理,查询 LTAK 与 LTAP,取最后一条转储订单行的确认时间判定“拣配完成”。查看交货抬头状态 VBUK-PODAT 以识别“交货证明(POD)已确认”。
- 抽取开票与收款相关事件:根据 VBFA 的开票单号,查询 VBRK 与 VBRP 获取“发票已创建”和“发票已冲销”(VBRK-FKSTO = 'X')。识别“已收款”时,将 VBRK 发票关联到 BKPF 会计凭证,再在 BSAD 中找到清账凭证及清账日期。
- 抽取基于状态的事件:使用状态表 VBUP(行项目状态)与 VBUK(抬头状态)推断业务事件。例如,当 VBUP-GBSTA 等于 'C' 时,行项目视为“订单行已关闭”。当所有相关行项目均设置了“拒绝原因”(VBAP-ABGRU)时,订单视为“订单已取消”。
- 合并与格式化:将捕获的所有事件合并为一个最终内部表。确保每条事件记录的属性(SalesOrder、Activity、StartTime、User 等)填写正确,并加入 SourceSystem 与 LastDataUpdate 的时间戳。
- 生成输出文件:使用函数模块 GUI_DOWNLOAD 或方法 cl_gui_frontend_services=>gui_download,将最终内部表导出为本地 CSV 文件,并确保以 UTF-8 编码保存。
配置
- 前提条件:具备 ABAP 开发权限(如可访问事务码 SE38),并对所需 SAP 表拥有读取权限,包括 VBAK、VBAP、CDHDR、CDPOS、VBFA、LIKP、LIPS、VBRK、VBRP、MKPF、MSEG 和 BSAD。
- 选择参数:程序需提供带筛选条件的选择屏幕。关键参数包括:
- 日期范围:必填,按销售订单创建日期(VBAK-ERDAT)限定。建议先选取近3–6个月,数据量更易控制。
- 销售组织:通过 VBAK-VKORG 筛选,聚焦特定业务单元。
- 销售单据类型:使用 VBAK-AUART,仅保留相关订单类型(如标准订单),排除其他类型(如报价、退货)。
- 性能注意事项:从变更日志表(CDHDR、CDPOS)和单据流(VBFA)抽取大数据量时可能非常慢。请在 WHERE 子句中优先使用索引字段进行优化。若需大批量抽取,建议通过事务码 SM36 将程序安排为离峰时段运行的后台作业。
- 变更日志激活:该方法依赖 SAP 的变更文档功能。请确认关键字段已开启变更记录(如 LIFSK、CMGST、ABGRU)。可在事务码 SCDO 中检查对象 VERKBELEG。
a 查询示例 abap
REPORT Z_O2C_PM_EXTRACTOR.
*&---------------------------------------------------------------------*
*& Data Declarations
*&---------------------------------------------------------------------*
TABLES: vbak.
TYPES: BEGIN OF ty_event_log,
salesorder TYPE vbeln_va,
activity TYPE string,
starttime TYPE string,
sourcesystem TYPE logsys,
lastdataupdate TYPE string,
user TYPE ernam,
customernumber TYPE kunnr,
salesorganization TYPE vkorg,
netamount TYPE netwr,
materialnumber TYPE matnr,
deliveryblock TYPE lifsk,
rejectionreason TYPE abgru,
salesordercycletime TYPE string, " Placeholder for calculation
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
DATA: gs_event_log TYPE ty_event_log.
DATA: gv_sysid TYPE logsys.
DATA: gv_last_update TYPE string.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_erdat FOR vbak-erdat OBLIGATORY,
s_vkorg FOR vbak-vkorg,
s_auart FOR vbak-auart.
PARAMETERS: p_file TYPE rlgrap-filename OBLIGATORY DEFAULT 'C:\temp\o2c_event_log.csv'.
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET'
IMPORTING
own_logical_system = gv_sysid.
CONCATENATE sy-datum sy-uzeit INTO gv_last_update.
PERFORM get_base_data.
PERFORM write_output_file.
*&---------------------------------------------------------------------*
*& Form get_base_data
*&---------------------------------------------------------------------*
FORM get_base_data.
TYPES: BEGIN OF ty_order_item,
vbeln TYPE vbeln_va,
posnr TYPE posnr_va,
erdat TYPE erdat,
erzet TYPE erzet,
ernam TYPE ernam,
kunnr TYPE kunnr,
vkorg TYPE vkorg,
netwr TYPE netwr_ak,
matnr TYPE matnr,
lifsk TYPE lifsk,
abgru TYPE abgru,
END OF ty_order_item.
DATA: lt_order_items TYPE TABLE OF ty_order_item.
SELECT h~vbeln i~posnr h~erdat h~erzet h~ernam h~kunnr h~vkorg h~netwr i~matnr h~lifsk i~abgru
INTO TABLE lt_order_items
FROM vbak AS h
INNER JOIN vbap AS i ON h~vbeln = i~vbeln
WHERE h~erdat IN s_erdat
AND h~vkorg IN s_vkorg
AND h~auart IN s_auart.
CHECK sy-subrc = 0.
DATA(lt_vbeln_range) = VALUE rsdsselopt_t(
FOR <fs_item> IN lt_order_items WHERE ( vbeln = <fs_item>-vbeln )
( sign = 'I' option = 'EQ' low = <fs_item>-vbeln ) ).
SORT lt_vbeln_range BY low.
DELETE ADJACENT DUPLICATES FROM lt_vbeln_range COMPARING low.
PERFORM extract_order_created USING lt_order_items.
PERFORM extract_changes USING lt_vbeln_range lt_order_items.
PERFORM extract_doc_flow_events USING lt_vbeln_range lt_order_items.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_order_created
*&---------------------------------------------------------------------*
FORM extract_order_created USING it_order_items TYPE ANY TABLE.
FIELD-SYMBOLS: <fs_item> TYPE any.
DATA: lt_unique_orders TYPE HASHED TABLE OF vbeln_va WITH UNIQUE KEY table_line.
lt_unique_orders = VALUE #( FOR <order> IN it_order_items ( CONV vbeln_va( <order>-vbeln ) ) ).
LOOP AT it_order_items ASSIGNING <fs_item> WHERE table_line IN lt_unique_orders.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_item>-vbeln.
gs_event_log-activity = 'Sales Order Created'.
CONCATENATE <fs_item>-erdat <fs_item>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_item>-ernam.
gs_event_log-customernumber = <fs_item>-kunnr.
gs_event_log-salesorganization = <fs_item>-vkorg.
gs_event_log-netamount = <fs_item>-netwr.
APPEND gs_event_log TO gt_event_log.
DELETE lt_unique_orders WHERE table_line = <fs_item>-vbeln.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_changes
*&---------------------------------------------------------------------*
FORM extract_changes USING it_vbeln_range TYPE rsdsselopt_t it_order_items TYPE ANY TABLE.
DATA: lt_cdhdr TYPE TABLE OF cdhdr,
lt_cdpos TYPE TABLE OF cdpos.
SELECT * INTO TABLE lt_cdhdr FROM cdhdr
WHERE objectclas = 'VERKBELEG'
AND objectid IN it_vbeln_range
AND tcode = 'VA02'.
IF sy-subrc = 0.
SELECT * INTO TABLE lt_cdpos FROM cdpos
FOR ALL ENTRIES IN lt_cdhdr
WHERE objectclas = lt_cdhdr-objectclas
AND objectid = lt_cdhdr-objectid
AND changenr = lt_cdhdr-changenr.
ENDIF.
LOOP AT lt_cdhdr ASSIGNING FIELD-SYMBOL(<fs_cdhdr>).
DATA(lv_order_info) = REF #( it_order_items[ vbeln = <fs_cdhdr>-objectid ] ).
IF lv_order_info IS NOT BOUND. CONTINUE. ENDIF.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_cdhdr>-objectid.
gs_event_log-user = <fs_cdhdr>-username.
CONCATENATE <fs_cdhdr>-udate <fs_cdhdr>-utime INTO gs_event_log-starttime.
gs_event_log-customernumber = lv_order_info->kunnr.
gs_event_log-salesorganization = lv_order_info->vkorg.
gs_event_log-netamount = lv_order_info->netwr.
" Generic Change Event
gs_event_log-activity = 'Sales Order Changed'.
APPEND gs_event_log TO gt_event_log.
LOOP AT lt_cdpos ASSIGNING FIELD-SYMBOL(<fs_cdpos>)
WHERE objectclas = <fs_cdhdr>-objectclas
AND objectid = <fs_cdhdr>-objectid
AND changenr = <fs_cdhdr>-changenr.
CASE <fs_cdpos>-fname.
WHEN 'LIFSK'. " Delivery Block
gs_event_log-activity = 'Delivery Block Set'.
gs_event_log-deliveryblock = <fs_cdpos>-value_new.
APPEND gs_event_log TO gt_event_log.
WHEN 'CMGST'. " Credit Status
IF <fs_cdpos>-value_new = 'B'. " B = Credit Check OK
gs_event_log-activity = 'Credit Check Performed'.
APPEND gs_event_log TO gt_event_log.
ENDIF.
WHEN 'ABGRU'. " Rejection Reason
IF <fs_cdpos>-value_new IS NOT INITIAL.
gs_event_log-activity = 'Order Cancelled'.
gs_event_log-rejectionreason = <fs_cdpos>-value_new.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDCASE.
ENDLOOP.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_doc_flow_events
*&---------------------------------------------------------------------*
FORM extract_doc_flow_events USING it_vbeln_range TYPE rsdsselopt_t it_order_items TYPE ANY TABLE.
DATA: lt_vbfa TYPE TABLE OF vbfa,
lt_vbrk TYPE TABLE OF vbrk,
lt_likp TYPE TABLE OF likp,
lt_mseg TYPE TABLE OF mseg,
lt_bsad TYPE TABLE OF bsad,
lt_vbup TYPE TABLE OF vbup.
SELECT * INTO TABLE lt_vbfa FROM vbfa
WHERE vbelv IN it_vbeln_range
AND ( vbtyp_n = 'J' " Delivery
OR vbtyp_n = 'M' " Invoice
OR vbtyp_n = 'N' " Invoice Cancellation
OR vbtyp_n = 'R' ). " Goods Movement
IF lt_vbfa IS INITIAL. RETURN. ENDIF.
SELECT vbeln, erdat, erzet, ernam, fksto, belnr FROM vbrk INTO TABLE lt_vbrk
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbeln
AND ( lt_vbfa-vbtyp_n = 'M' OR lt_vbfa-vbtyp_n = 'N' ).
SELECT vbeln, erdat, erzet, ernam, podat FROM likp INTO TABLE lt_likp
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbeln AND lt_vbfa-vbtyp_n = 'J'.
SELECT mblnr, mjahr, zeile, bwart, budat, cpuzt, usnam FROM mseg INTO TABLE lt_mseg
FOR ALL ENTRIES IN lt_vbfa
WHERE mblnr = lt_vbfa-vbeln AND mjahr = lt_vbfa-mjahr AND zeile = lt_vbfa-posnn AND lt_vbfa-vbtyp_n = 'R' AND bwart = '601'.
SELECT augdt, belnr, gjahr, kunnr FROM bsad INTO TABLE lt_bsad
FOR ALL ENTRIES IN lt_vbrk
WHERE belnr = lt_vbrk-belnr AND gjahr = SUBSTRING( val = lt_vbrk-erdat len = 4 ).
SELECT vbeln, posnr, gbsta FROM vbup INTO TABLE lt_vbup
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbelv AND posnr = lt_vbfa-posnv.
LOOP AT lt_vbfa ASSIGNING FIELD-SYMBOL(<fs_vbfa>).
DATA(lv_order_info) = REF #( it_order_items[ vbeln = <fs_vbfa>-vbelv ] ).
IF lv_order_info IS NOT BOUND. CONTINUE. ENDIF.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_vbfa>-vbelv.
gs_event_log-customernumber = lv_order_info->kunnr.
gs_event_log-salesorganization = lv_order_info->vkorg.
gs_event_log-netamount = lv_order_info->netwr.
gs_event_log-materialnumber = lv_order_info->matnr.
CASE <fs_vbfa>-vbtyp_n.
WHEN 'J'. " Delivery
READ TABLE lt_likp ASSIGNING FIELD-SYMBOL(<fs_likp>) WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0.
gs_event_log-activity = 'Delivery Created'.
CONCATENATE <fs_likp>-erdat <fs_likp>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_likp>-ernam.
APPEND gs_event_log TO gt_event_log.
" Picking Completed - simplified logic, check status
gs_event_log-activity = 'Picking Completed'. APPEND gs_event_log TO gt_event_log.
" POD Confirmed
IF <fs_likp>-podat IS NOT INITIAL.
gs_event_log-activity = 'Proof Of Delivery Confirmed'.
gs_event_log-starttime = <fs_likp>-podat.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
WHEN 'R'. " Goods Issue
READ TABLE lt_mseg ASSIGNING FIELD-SYMBOL(<fs_mseg>) WITH KEY mblnr = <fs_vbfa>-vbeln mjahr = <fs_vbfa>-mjahr zeile = <fs_vbfa>-posnn.
IF sy-subrc = 0.
gs_event_log-activity = 'Goods Issued'.
CONCATENATE <fs_mseg>-budat <fs_mseg>-cpuzt INTO gs_event_log-starttime.
gs_event_log-user = <fs_mseg>-usnam.
APPEND gs_event_log TO gt_event_log.
ENDIF.
WHEN 'M'. " Invoice
READ TABLE lt_vbrk ASSIGNING FIELD-SYMBOL(<fs_vbrk>) WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0.
gs_event_log-activity = 'Invoice Created'.
CONCATENATE <fs_vbrk>-erdat <fs_vbrk>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_vbrk>-ernam.
APPEND gs_event_log TO gt_event_log.
" Payment Received
READ TABLE lt_bsad ASSIGNING FIELD-SYMBOL(<fs_bsad>) WITH KEY belnr = <fs_vbrk>-belnr.
IF sy-subrc = 0 AND <fs_bsad>-augdt IS NOT INITIAL.
gs_event_log-activity = 'Payment Received'.
gs_event_log-starttime = <fs_bsad>-augdt.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
WHEN 'N'. " Invoice Cancellation
READ TABLE lt_vbrk ASSIGNING <fs_vbrk> WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0 AND <fs_vbrk>-fksto = 'X'.
gs_event_log-activity = 'Invoice Cancelled'.
CONCATENATE <fs_vbrk>-erdat <fs_vbrk>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_vbrk>-ernam.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDCASE.
ENDLOOP.
" Infer other events from status
LOOP AT lt_vbup ASSIGNING FIELD-SYMBOL(<fs_vbup>).
IF <fs_vbup>-gbsta = 'C'.
DATA(lv_order_info_stat) = REF #( it_order_items[ vbeln = <fs_vbup>-vbeln ] ).
IF lv_order_info_stat IS NOT BOUND. CONTINUE. ENDIF.
gs_event_log-salesorder = <fs_vbup>-vbeln.
gs_event_log-activity = 'Order Item Closed'.
" Timestamp for closed is harder, using current time as placeholder
CONCATENATE sy-datum sy-uzeit INTO gs_event_log-starttime.
gs_event_log-user = sy-uname.
gs_event_log-customernumber = lv_order_info_stat->kunnr.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
" Order Confirmed (Simplified - assumes if not blocked it's confirmed)
LOOP AT it_order_items ASSIGNING FIELD-SYMBOL(<fs_item>).
IF <fs_item>-lifsk IS INITIAL.
gs_event_log-salesorder = <fs_item>-vbeln.
gs_event_log-activity = 'Order Confirmed'.
CONCATENATE <fs_item>-erdat <fs_item>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_item>-ernam.
gs_event_log-customernumber = <fs_item>-kunnr.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form write_output_file
*&---------------------------------------------------------------------*
FORM write_output_file.
DATA: lt_final_output TYPE TABLE OF ty_event_log.
" Add common fields
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_event>).
<fs_event>-sourcesystem = gv_sysid.
<fs_event>-lastdataupdate = gv_last_update.
ENDLOOP.
SORT gt_event_log BY salesorder starttime.
DELETE ADJACENT DUPLICATES FROM gt_event_log COMPARING ALL FIELDS.
lt_final_output = gt_event_log.
DATA: lt_fieldnames TYPE TABLE OF string.
APPEND 'SalesOrder' TO lt_fieldnames.
APPEND 'Activity' TO lt_fieldnames.
APPEND 'StartTime' TO lt_fieldnames.
APPEND 'SourceSystem' TO lt_fieldnames.
APPEND 'LastDataUpdate' TO lt_fieldnames.
APPEND 'User' TO lt_fieldnames.
APPEND 'CustomerNumber' TO lt_fieldnames.
APPEND 'SalesOrganization' TO lt_fieldnames.
APPEND 'NetAmount' TO lt_fieldnames.
APPEND 'MaterialNumber' TO lt_fieldnames.
APPEND 'DeliveryBlock' TO lt_fieldnames.
APPEND 'RejectionReason' TO lt_fieldnames.
APPEND 'SalesOrderCycleTime' TO lt_fieldnames.
DATA(lv_header) = REDUCE string(
INIT s = ''
FOR field IN lt_fieldnames
NEXT s = s && COND #( WHEN s = '' THEN field ELSE |,{ field }| ) ).
DATA: lt_file_content TYPE TABLE OF string.
APPEND lv_header TO lt_file_content.
LOOP AT lt_final_output INTO DATA(ls_output).
DATA(lv_line) = |"{ ls_output-salesorder }","{ ls_output-activity }","{ ls_output-starttime }","{ ls_output-sourcesystem }","{ ls_output-lastdataupdate }","{ ls_output-user }","{ ls_output-customernumber }","{ ls_output-salesorganization }",{ ls_output-netamount },"{ ls_output-materialnumber }","{ ls_output-deliveryblock }","{ ls_output-rejectionreason }","{ ls_output-salesordercycletime }"|.
APPEND lv_line TO lt_file_content.
ENDLOOP.
cl_gui_frontend_services=>gui_download(
EXPORTING
filename = p_file
filetype = 'ASC'
CHANGING
data_tab = lt_file_content ).
ENDFORM.步骤
- 前提条件:确保您对底层 SAP ECC 数据库拥有直接的只读访问权限。您需要使用 DBeaver、SQL Server Management Studio 或 Oracle SQL Developer 等数据库客户端进行连接并执行查询。
- 获取 SQL 脚本:复制本文档“query”部分提供的完整 SQL 语句。
- 连接数据库:打开数据库客户端,连接到 SAP ECC 数据库实例。您需要服务器地址、端口、数据库名称以及相应的登录凭据。
- 配置查询:将 SQL 脚本粘贴到新的查询编辑器窗口。在主 CTE(Common Table Expression)SalesOrders 中找到配置段。把开始日期('{StartDate}')、结束日期('{EndDate}')、销售组织('{SalesOrgs}')和单据类型('{DocTypes}')的占位符替换为您的实际取值。
- 执行查询:运行已配置的 SQL 脚本。根据时间范围和 SAP 数据库规模,查询可能需要数分钟完成。
- 检查结果:查询完成后会显示结果集。快速浏览,确认包含期望的列(SalesOrder、Activity、StartTime 等),且不同活动都有返回记录。
- 导出数据:使用数据库客户端的导出功能,将结果集保存为 CSV 文件。建议使用易于识别的文件名,例如 SAP_O2C_Event_Log.csv。
- 为 ProcessMind 格式化:在电子表格工具中打开 CSV 文件。确认列名与要求的属性完全一致(如 SalesOrder、Activity、StartTime)。确保 StartTime 与 LastDataUpdate 的日期时间格式统一且被 ProcessMind 支持,例如 YYYY-MM-DD HH:MI:SS。
- 上传到 ProcessMind:将最终整理好的 CSV 文件上传到您的 ProcessMind 项目进行分析。
配置
- 日期范围:查询通过占位符('{StartDate}' 和 '{EndDate}')按创建日期(VBAK.ERDAT)筛选销售订单。建议先选取近3–6个月的数据,既具代表性,又避免给数据库带来过大压力。
- 销售组织筛选:使用 '{SalesOrgs}' 占位符,仅提取指定的销售组织(如 '1000'、'2000')。这样能聚焦分析并提升查询性能。
- 单据类型筛选:使用 '{DocTypes}' 占位符,限定销售订单类型(例如标准订单 'OR')。可将零价交货、退货等与主流程无关的单据排除在外。
- 来源系统标识:通过硬编码占位符 '{SourceSystemName}' 为每条记录打上来源系统标签。请设置为可识别的 SAP ECC 实例名称(如 SAP_ECC_PRD)。
- 数据库兼容性:用于合并日期和时间字段的函数 [Your DB-specific timestamp function] 仅为占位符。请根据所用数据库替换为正确的函数(例如 SAP HANA 使用 TO_TIMESTAMP(CONCAT(CDHDR.UDATE, CDHDR.UZEIT), 'YYYYMMDDHH24MISS'),SQL Server 使用 CAST(CDHDR.UDATE AS DATETIME) + CAST(CDHDR.UZEIT AS DATETIME))。
- 前提条件:此方法需要直接的只读数据库凭据。数据库用户必须有权访问查询涉及的所有表,包括 VBAK、VBAP、VBFA、CDHDR、CDPOS、LIKP、VBRK 和 BSAD。
a 查询示例 sql
WITH SalesOrders AS (
SELECT VBELN
FROM VBAK
WHERE ERDAT BETWEEN '{StartDate}' AND '{EndDate}' -- Filter by creation date
AND VKORG IN ('{SalesOrgs}') -- Filter by Sales Organization(s)
AND AUART IN ('{DocTypes}') -- Filter by Sales Document Type(s)
)
-- 1. Sales Order Created
SELECT
vbak.VBELN AS "SalesOrder",
'Sales Order Created' AS "Activity",
[Your DB-specific timestamp function](vbak.ERDAT, vbak.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbak.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBAK vbak
JOIN SalesOrders so ON vbak.VBELN = so.VBELN
UNION ALL
-- 2. Sales Order Changed
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Sales Order Changed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG' AND cdhdr.TCODE IN ('VA02')
UNION ALL
-- 3. Credit Check Performed (Release)
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Credit Check Performed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'CMGST'
AND cdpos.VALUE_NEW = 'B' -- Credit status 'Released'
UNION ALL
-- 4. Order Confirmed (Overall status not blocked)
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Order Confirmed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'GBSTK'
AND cdpos.VALUE_OLD <> 'A' AND cdpos.VALUE_NEW = 'A' -- Status changes to 'Not yet processed'
UNION ALL
-- 5. Delivery Block Set
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Delivery Block Set' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
cdpos.VALUE_NEW AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBAK'
AND cdpos.FNAME = 'LIFSK'
AND cdpos.VALUE_NEW IS NOT NULL AND cdpos.VALUE_NEW <> ''
UNION ALL
-- 6. Delivery Created
SELECT
vbfa.VBELV AS "SalesOrder",
'Delivery Created' AS "Activity",
[Your DB-specific timestamp function](likp.ERDAT, likp.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
likp.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN LIKP likp ON vbfa.VBELN = likp.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J'
UNION ALL
-- 7. Picking Completed
SELECT
vbfa.VBELV AS "SalesOrder",
'Picking Completed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN CDHDR cdhdr ON vbfa.VBELN = cdhdr.OBJECTID
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J'
AND cdhdr.OBJECTCLASS = 'LIEFERUNG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'PKSTK'
AND cdpos.VALUE_NEW = 'C'
UNION ALL
-- 8. Goods Issued
SELECT
vbfa_gi.VBELV AS "SalesOrder",
'Goods Issued' AS "Activity",
[Your DB-specific timestamp function](mkpf.BUDAT, mkpf.CPUTM) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
mkpf.USNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa_gi
JOIN SalesOrders so ON vbfa_gi.VBELV = so.VBELN
JOIN MKPF mkpf ON vbfa_gi.VBELN = mkpf.XBLNR -- XBLNR is Reference Document Number
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa_gi.VBTYP_V = 'J' AND vbfa_gi.VBTYP_N = 'R'
UNION ALL
-- 9. Proof Of Delivery Confirmed
SELECT
vbfa.VBELV AS "SalesOrder",
'Proof Of Delivery Confirmed' AS "Activity",
[Your DB-specific timestamp function](likp.PODAT, '000000') AS "StartTime", -- PODAT is only a date
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
likp.AENAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN LIKP likp ON vbfa.VBELN = likp.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J' AND likp.PODAT IS NOT NULL AND likp.PODAT <> '00000000'
UNION ALL
-- 10. Invoice Created
SELECT
vbfa.VBELV AS "SalesOrder",
'Invoice Created' AS "Activity",
[Your DB-specific timestamp function](vbrk.ERDAT, vbrk.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbrk.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'M'
UNION ALL
-- 11. Invoice Cancelled
SELECT
vbfa.VBELV AS "SalesOrder",
'Invoice Cancelled' AS "Activity",
[Your DB-specific timestamp function](vbrk.ERDAT, vbrk.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbrk.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'M' AND vbfa.VBTYP_N = 'N'
UNION ALL
-- 12. Payment Received
SELECT
vbfa.VBELV AS "SalesOrder",
'Payment Received' AS "Activity",
[Your DB-specific timestamp function](bsad.AUGDT, '000000') AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
NULL AS "User", -- Clearing user not readily available here
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN BSAD bsad ON vbrk.VBELN = bsad.VBLNR
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'M'
AND bsad.AUGDT IS NOT NULL AND bsad.AUGDT <> '00000000'
UNION ALL
-- 13. Order Item Closed
SELECT DISTINCT
cdhdr.OBJECTID AS "SalesOrder",
'Order Item Closed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
vbap.MATNR AS "MaterialNumber",
NULL AS "DeliveryBlock",
vbap.ABGRU AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAP vbap ON cdhdr.OBJECTID = vbap.VBELN AND SUBSTRING(cdpos.TABKEY, 4, 6) = vbap.POSNR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUP'
AND cdpos.FNAME = 'GBSTA'
AND cdpos.VALUE_NEW = 'C' -- Item is completely processed
UNION ALL
-- 14. Order Cancelled
SELECT DISTINCT
cdhdr.OBJECTID AS "SalesOrder",
'Order Cancelled' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
vbap.MATNR AS "MaterialNumber",
NULL AS "DeliveryBlock",
cdpos.VALUE_NEW AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAP vbap ON cdhdr.OBJECTID = vbap.VBELN AND SUBSTRING(cdpos.TABKEY, 4, 6) = vbap.POSNR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBAP'
AND cdpos.FNAME = 'ABGRU'
AND cdpos.VALUE_NEW IS NOT NULL AND cdpos.VALUE_NEW <> '';