您的采购到付款流程:采购订单数据模板
您的采购到付款流程:采购订单数据模板
- 建议收集的属性
- 需要跟踪的关键活动
- SAP ECC数据提取指南
采购到付款流程:采购订单属性
| 名称 | 说明 | ||
|---|---|---|---|
| 事件时间 EventTime | 活动发生的准确日期和时间。 | ||
| 说明 此时间戳标记事件发生的准确时刻,例如采购订单获批或收货过账的时间,并确定案例中所有活动的先后顺序。 时间戳是流程挖掘的基础,可支持各类时间分析,包括计算活动间的周期时间、发现延误、分析流程吞吐量,以及衡量绩效是否达到服务级别协议(SLA)的要求。 重要性 此时间戳对于计算周期时间、识别瓶颈等所有基于时长的指标,以及按时间顺序排列事件都至关重要。 获取途径 根据SAP表中的多个日期和时间字段生成,例如EKKO-AEDAT(变更日期)、CDHDR-UDATE/UTIME(变更日志时间戳)或EKBE-BUDAT(过账日期)。 示例 2023-04-15T10:05:31Z2023-04-16T14:22:00Z2023-05-01T09:00:15Z | |||
| 活动 Activity | 采购订单生命周期中发生的具体业务事件或步骤的名称。 | ||
| 说明 此属性描述流程中的单个步骤,例如“采购订单已创建”“采购订单已批准”或“收货已过账”。这些活动按顺序排列,构成每个采购订单的流程路径。 分析活动的顺序、频率及其间隔时长,是流程挖掘的核心。此类分析有助于发现瓶颈、返工循环和偏离标准流程的情况,从而有针对性地改进流程并推动标准化。 重要性 活动定义了流程中的各个步骤。分析活动顺序和时间,有助于了解实际流程路径、瓶颈和偏差。 获取途径 根据SAP中的多个表和事务日志生成,例如用于记录变更的CDHDR/CDPOS、用于收货/发票收据的EKBE以及用于采购申请的EBAN。通常需要自定义逻辑或提取程序来生成。 示例 创建采购订单采购订单已批准已过账收货 | |||
| 采购订单 PurchaseOrder | 采购订单(PO)单据的唯一标识符,也是跟踪采购流程的主要案例标识。 | ||
| 说明 采购订单编号是关联从创建到最终收货和完成的所有活动的核心标识符。每个唯一的采购订单编号都代表一个独立的采购流程实例。 在流程挖掘中,此属性对于还原每笔采购的端到端历程至关重要。它支持详细分析每笔订单的周期时间、流程差异和合规情况,并构成整个流程模型的基础。 重要性 这是关联所有相关事件的核心标识符,可用于分析每个采购订单的完整生命周期。 获取途径 表:EKKO,字段:EBELN 示例 450001762345000176244500017625 | |||
| 供应商编号 VendorNumber | 供应商的唯一标识符。 | ||
| 说明 此代码用于唯一标识提供所采购货物或服务的供应商,是采购流程中的关键主数据。 此属性对于以供应商为中心的分析至关重要。它支持评估供应商交付绩效、比较不同供应商的交付周期以及分析支出模式,也是“供应商交付绩效”仪表板的主要分析维度。 重要性 支持供应商绩效分析,帮助识别可靠的供应商,以及导致延误或质量问题的供应商。 获取途径 表:EKKO,字段:LIFNR 示例 100345V-20598700112 | |||
| 公司代码 CompanyCode | 发起采购的法人实体或公司的标识符。 | ||
| 说明 公司代码在SAP中代表一个独立法人实体。所有交易都按公司代码过账,因此它是基础组织单元。 按公司代码分析流程,有助于比较不同业务单元或国家的采购效率和合规情况。您可以据此发现可供其他实体借鉴的最佳实践,或找出流程执行困难的特定单元。 重要性 表示法人实体,可用于比较组织不同部分的流程绩效并检查合规情况。 获取途径 表:EKKO,字段:BUKRS 示例 10002100US01 | |||
| 单据类型 DocumentType | 用于区分不同类型采购订单的代码。 | ||
| 说明 单据类型是SAP中的一项配置,用于控制采购订单的编号范围、字段选择和整体流程路径。例如,标准采购订单、服务采购订单或库存转储订单可能使用不同类型。 此属性是重要的分析维度,因为不同单据类型通常遵循有意区分的流程。按单据类型筛选,可更准确地比较周期时间和流程路径。 重要性 区分不同类型的采购流程(例如标准采购、服务采购和退货),这些流程通常有不同的路径和绩效预期。 获取途径 表:EKKO,字段:BSART 示例 NBFOUB | |||
| 物料组 MaterialGroup | 用于归类具有相似特征的物料或服务。 | ||
| 说明 物料组也称采购类别,用于对采购的货物或服务类型进行分类,例如“IT硬件”“办公用品”或“专业服务”。 此属性对于支出分析和了解采购模式至关重要。您可以按类别筛选流程,分析不同类别的处理方式、审批人以及供应商。它也是“采购订单价值分析”仪表板的重要维度。 重要性 支持按产品或服务类别细分流程,揭示不同支出类型对应的行为、周期时间或供应商差异。 获取途径 表:EKPO,字段:MATKL 示例 00101IT_HWCONSULT | |||
| 用户名 UserName | 执行活动的人员的用户ID。 | ||
| 说明 此属性记录创建、变更或批准单据的员工SAP用户名。对于自动执行的步骤,可能显示系统用户或批处理用户ID。 按用户分析有助于发现培训需求、表现突出的员工或潜在的合规问题。它也是构建工作量分配、审批矩阵合规情况及团队或个人绩效相关仪表板的关键数据。 重要性 将用户操作关联到具体人员,以便分析用户绩效、工作量及其对合规要求的遵循情况。 获取途径 表:EKKO,字段:ERNAM(创建者);表:CDHDR,字段:USERNAME(变更者)。 示例 JSMITHMBROWNBATCH_USER | |||
| 订单金额 OrderAmount | 采购订单行项目的货币总额。 | ||
| 说明 此属性表示采购订单中特定行项目的总金额,按数量乘以净价计算。要计算整个采购订单的金额,需要汇总各行项目金额。 按订单金额分析流程,对于识别需要更严格控制或采用不同审批路径的高金额交易至关重要。此属性支持“采购订单价值分析”仪表板,并有助于优先改进财务影响最大的订单流程。 重要性 量化每笔采购的财务影响,支持按金额分析、优先关注高金额订单或发现节省成本的机会。 获取途径 表:EKPO,字段:NETWR(订单净值)。 示例 1500.00250.7512345.50 | |||
| 供应商名称 VendorName | 供应商的法定名称。 | ||
| 说明 供应商的描述性名称,比供应商编号更便于用户识别,通常取自供应商主数据。 供应商编号用于关联数据和唯一标识,供应商名称则便于面向用户的仪表板和报告使用。对于不熟悉供应商代码的业务用户,名称能让分析更直观、易懂。 重要性 以易读的名称显示供应商信息,让业务用户更容易理解仪表板和报告。 获取途径 表:LFA1,字段:NAME1。需要通过EKKO-LIFNR与LFA1-LIFNR进行关联。 示例 Staples Inc.Global Tech SolutionsOffice Supply Co. | |||
| 工厂 Plant | 货物的交付地点或工厂。 | ||
| 说明 工厂是代表生产设施、仓库或其他接收货物或服务地点的组织单位。 按工厂分析有助于了解采购流程在不同地区的差异。例如,可以发现供应商向特定地点交货所需时间的差异,或找出收货流程效率较低的工厂,从而分析收货是否及时。 重要性 指定交付地点,可用于分析区域流程差异和物流绩效。 获取途径 表:EKPO,字段:WERKS 示例 100011002000 | |||
| 拒绝原因 RejectionReason | 说明采购申请或采购订单被拒绝原因的代码或文本。 | ||
| 说明 此属性记录采购订单在审批工作流中被拒绝时提供的具体原因,是了解返工和延误根本原因的重要信息。 分析拒绝原因有助于发现常见问题,例如价格错误、预算超支或供应商选择不符合要求。借助这些信息,业务团队可以解决问题根源、提高采购订单初始创建质量并简化审批流程。 重要性 直接揭示审批失败的原因,帮助有针对性地改进,减少返工并缩短审批周期。 获取途径 此信息可能不易查找,可能存储在长文本字段中,也可能取决于自定义工作流配置。通常需要具备特定的实施知识。 示例 价格错误预算超支重复申请 | |||
| 数据上次更新时间 LastDataUpdate | 表示数据上次从源系统刷新时间的时间戳。 | ||
| 说明 此属性记录最近一次数据提取或更新的日期和时间,说明所分析数据的新旧程度。 在仪表板中显示此信息,有助于用户了解洞察基于的是近实时数据还是历史快照。这有助于管理用户预期,并确保决策依据的数据时效明确。 重要性 向用户说明数据的时效性,帮助他们了解分析是否反映了运营的最新状态。 获取途径 此时间戳由数据提取或ETL流程在执行时生成并添加。 示例 2023-10-27T02:00:00Z2023-10-28T02:00:00Z | |||
| 是否为审批后变更 IsPostApprovalChange | 用于标记采购订单是否在首次审批后发生变更。 | ||
| 说明 对于同一采购订单,如果在“采购订单已批准”活动之后检测到“采购订单已变更”活动,此布尔属性的值为true。借此可识别流程后期发生的问题变更。 此计算字段直接用于“审批后采购订单变更率”KPI和“采购订单返工与变更”仪表板。它有助于量化并突出显示可能导致延误、需要重新审批的变更,揭示初始需求定义或范围界定环节的问题。 重要性 直接衡量审批后的返工情况,这是反映流程稳定性和效率的关键KPI。比率偏高通常表明前期需求定义存在问题。 获取途径 此计算属性根据事件日志中的活动顺序得出。 示例 truefalse | |||
| 是否按时交付 IsOnTimeDelivery | 用于标记货物是否在要求的交付日期当天或之前收到。 | ||
| 说明 如果“已过账收货”活动的时间戳不晚于“要求交付日期”,此布尔属性的值为true。它可以清晰地显示每个采购订单行项目的交付结果。 此属性是“按时收货率”KPI的基础。通过汇总和筛选按时与延迟交付的数据,可简化供应商绩效和内部收货效率分析。 重要性 清晰衡量交付是否及时,直接支持供应商绩效KPI和仪表板。 获取途径 此计算属性通过比较收货过账日期(EKBE-BUDAT)与要求交付日期(EKPO-EINDT)得出。 示例 truefalse | |||
| 源系统 SourceSystem | 提取数据的系统。 | ||
| 说明 此属性标识数据来源,通常是SAP ECC实例标识符(例如“ECC_PROD_100”)。在包含多个系统的环境中,它有助于区分数据源。 对于数据治理和数据沿袭,了解源系统至关重要。这有助于确保数据完整性,并排查数据提取或质量问题,尤其是在合并来自不同ERP系统或模块的数据时。 重要性 标识数据来源,对于数据治理、验证以及管理跨多个系统的分析至关重要。 获取途径 通常在数据提取过程中添加静态值,用于标记数据集的来源系统。 示例 SAP_ECC_PRODECC_EU_100S4H_FIN | |||
| 要求交货日期 RequestedDeliveryDate | 业务部门要求供应商交付货物或服务的日期。 | ||
| 说明 这是采购订单中指定的目标交货日期,可作为衡量实际交付绩效的基准。 此日期对于计算“准时收货率”指标至关重要。将实际收货日期与要求交货日期进行比较,组织可以量化评估供应商可靠性和内部收货效率,并为“供应商交付绩效”仪表板提供数据支持。 重要性 这是交付目标日期,对于计算准时绩效指标和评估供应商可靠性至关重要。 获取途径 表:EKPO,字段:EINDT 示例 2023-06-102023-07-222023-08-01 | |||
| 货币 Currency | 采购订单金额所用的货币代码。 | ||
| 说明 此属性指定采购订单金额所用的货币,例如USD、EUR或GBP,为所有金额提供必要的背景信息。 对于跨国组织,货币信息是准确开展财务分析的必要条件。它支持正确汇总和比较订单金额,所有货币指标都必须结合相应币种解读。 重要性 为所有金额提供必要的背景信息,确保财务分析准确,尤其适用于跨国组织。 获取途径 表:EKKO,字段:WAERS 示例 USDEURJPY | |||
| 采购申请 PurchaseRequisition | 前序采购申请的标识符。 | ||
| 说明 此属性将采购订单关联到其来源采购申请。并非所有采购订单都有前序采购申请。 此关联对于分析“采购申请到订单转换”仪表板和“采购申请到采购订单转换率”指标至关重要。它支持衡量从初始申请到正式订单创建的上游流程效率,并识别未通过采购申请直接创建的不合规采购订单。 重要性 将采购订单关联到其来源申请,以便分析采购申请到采购订单的转换流程,并识别没有前序采购申请的订单。 获取途径 表:EKPO,字段:BANFN 示例 1001589010015891 | |||
| 采购组 PurchasingGroup | 负责采购活动的具体采购员或采购团队。 | ||
| 说明 采购组代表负责某项采购活动的采购员或团队,也是供应商的主要联系人。 与采购组织相比,此属性支持更细粒度的分析。它有助于了解采购员之间的工作量分配和个人绩效差异,为资源配置和培训计划提供依据。 重要性 按采购员或团队细分,清晰呈现采购负责人,便于详细分析工作量和绩效。 获取途径 表:EKKO,字段:EKGRP 示例 001002N01 | |||
| 采购组织 PurchasingOrganization | 负责议价以及采购物料或服务的组织单元。 | ||
| 说明 采购组织是SAP中的关键组织单元,负责采购活动。它可以集中管理整个公司采购,也可以按工厂或地区分散管理。 按采购组织分析流程绩效,有助于识别效率较高的采购团队。您可以比较不同组织单元的周期时间、返工率和成本等指标,发现最佳实践和需要支持的领域。 重要性 标识负责采购的团队,支持比较和分析不同组织单元的绩效。 获取途径 表:EKKO,字段:EKORG 示例 1000US01DE01 | |||
采购到付款流程:采购订单活动
| 活动 | 说明 | ||
|---|---|---|---|
| 创建采购申请 | 此活动表示正式提出货物或服务需求。用户保存新的采购申请单据时(例如使用ME51N事务),系统会记录这一明确事件,并在EBAN表中生成唯一记录。 | ||
| 重要性 这是采购流程的主要起点。分析从此事件到创建采购订单所需的时间,有助于衡量将内部需求转化为可执行订单的效率。 获取途径 在采购申请抬头表(EBAN)中创建记录时记录。事件时间戳取自创建日期(EBAN-BADAT)和时间。 采集 根据创建日期识别EBAN表中的新增记录。 事件类型 explicit | |||
| 创建采购订单 | 此活动表示正式采购订单单据已创建,该单据是与供应商签订的具有约束力的合同。用户创建并保存采购订单时(例如通过ME21N事务),系统会记录这一明确事件,并在EKKO和EKPO表中生成记录。 | ||
| 重要性 标志着采购订单生命周期正式开始。这是衡量采购申请到采购订单的转换时间以及端到端订单履行时间的重要节点。 获取途径 从采购订单抬头表(EKKO)中对应采购订单编号(EKKO-EBELN)的创建日期(EKKO-AEDAT)获取。 采集 使用EKKO表中每个新采购订单的创建时间戳。 事件类型 explicit | |||
| 已过账收货 | 此活动表示已收到供应商交付的、对应特定采购订单的实物货物。过账收货是一项明确操作(例如通过MIGO事务),会生成物料凭证并更新库存。 | ||
| 重要性 这是跟踪供应商交付绩效以及启动发票校验流程的重要节点,可用于计算准时交付率和收货及时性。 获取途径 创建物料凭证时记录。事件时间戳取自物料凭证抬头表(MKPF)中的过账日期(MKPF-BUDAT)或创建日期(MKPF-CPUDT),并通过项目表(MSEG)关联到采购订单。 采集 对于引用该采购订单的物料凭证,使用MKPF表中的过账或创建时间戳。 事件类型 explicit | |||
| 采购订单已发送给供应商 | 此活动标志着已批准的采购订单正式发送给供应商,例如通过EDI、电子邮件或打印件发送。当输出消息成功处理时,消息控制表会记录这一明确事件。 | ||
| 重要性 这是供应商交付周期开始计时的重要节点。分析从此事件到收货所需的时间,是评估供应商绩效和交付及时性的关键。 获取途径 记录在消息状态表(NAST)中。对于相关采购订单输出类型,当处理状态(NAST-VSTAT)为“1”(处理成功)时,可从NAST-DATVR和NAST-UHRVR获取时间戳。 采集 使用NAST表中采购订单输出消息的处理时间戳。 事件类型 explicit | |||
| 采购订单已完成 | 表示采购订单项目已全部交付。此事件通常根据采购订单项目上的“交货完成”指示符是否由系统自动设置或由用户手动设置来推断。 | ||
| 重要性 此活动是订单履行流程的逻辑终点,对于计算从创建到完成的端到端采购订单周期时间至关重要。 获取途径 根据变更单据(CDHDR/CDPOS)推断。当采购订单项目的“交货完成”指示符(EKPO-ELIKZ)设为“X”时,变更单据会记录此信息。最后一个项目标记为完成时,可能表示整个采购订单已完成。 采集 在变更单据中查找EKPO-ELIKZ标志被设置的时间戳。 事件类型 inferred | |||
| 采购订单已批准 | 表示采购订单已最终获批,可以发送给供应商。通常根据采购订单发布状态变为“完全发布”或“已批准”来推断这一关键节点。 | ||
| 重要性 此活动对于计算采购订单审批周期时间指标、发现审批工作流中的瓶颈至关重要。将订单发送给供应商等后续活动通常都以此为前提。 获取途径 跟踪采购订单抬头表(EKKO)的变更日志(CDHDR/CDPOS),查找最终发布代码的应用时间,或整体发布状态指示符(EKKO-FRGKE)设为“已发布”的时间,据此推断此事件。 采集 识别采购订单整体发布状态(EKKO-FRGKE)变为最终批准状态的时间戳。 事件类型 inferred | |||
| 已录入服务确认 | 对于服务类采购订单,此活动表示服务已完成确认。创建服务录入单(例如通过ML81N事务)时,系统会记录这一明确事件。 | ||
| 重要性 这相当于服务类采购的收货,是跟踪服务订单履行情况的必要环节,并会启动服务付款的财务流程。 获取途径 从服务录入单抬头表(ESSR)中的创建日期(ESSR-ERDAT)获取。与采购订单的关联信息位于ESLL表中。 采集 对于关联到采购订单的服务录入单,使用ESSR表中的创建时间戳。 事件类型 explicit | |||
| 已执行质量检验 | 表示收到的货物已完成质量检验。通常根据质量管理模块中的检验批是否已作出使用决策来推断此活动。检验批通常在收货时创建。 | ||
| 重要性 对于质量要求严格的行业,此活动有助于分析检验流程的耗时和结果。检验延误可能导致收货与货物可供使用之间出现瓶颈。 获取途径 根据质量管理模块的数据推断。收货时会在QALS表中创建检验批;在QAVE表中创建使用决策时,即标记此活动,其中包含时间戳。 采集 在QAVE表中查找与物料凭证关联的检验批的使用决策时间戳。 事件类型 inferred | |||
| 已提交采购订单审批 | 表示已创建或变更的采购订单已根据配置的发布策略提交审批。当发布策略启动且采购订单进入待审批状态时,可推断此事件。 | ||
| 重要性 区分采购订单创建时间与审批流程开始时间,有助于准确衡量审批周期时间指标,并揭示审批工作流启动前的延迟。 获取途径 根据采购订单(对象EINKBELEG)的变更单据(CDHDR/CDPOS)推断。若单据显示发布状态首次设置,或整体发布状态(EKKO-FRGKE)首次设为表示审批流程已启动的值,即可识别此事件。 采集 识别触发采购订单发布策略的首条变更单据记录。 事件类型 inferred | |||
| 货物已退回 | 表示将先前收到的货物退还给供应商,通常是因为质量问题或发货错误。使用退货专用移动类型过账物料凭证时,系统会记录这一明确事件。 | ||
| 重要性 此活动反映供应商质量或订单准确性问题,也是流程返工的重要指标。它对于计算收货差异率指标至关重要。 获取途径 使用退货移动类型(例如“122”,表示退货给供应商)时,会在物料凭证表(MKPF/MSEG)中记录。过账日期(MKPF-BUDAT)作为时间戳。 采集 识别引用原始采购订单且使用退货移动类型(例如122)的物料凭证。 事件类型 explicit | |||
| 采购申请已批准 | 表示采购申请已正式获批,可以转为采购订单。此事件根据采购申请数据中的发布状态字段变化推断,相关变化由SAP发布策略工作流跟踪。 | ||
| 重要性 跟踪审批情况对于发现下单前阶段的瓶颈、确保遵循审批政策至关重要。此阶段的延误会直接影响整体采购周期时间。 获取途径 根据采购申请表(EBAN)的变更日志推断,重点监控发布状态字段(例如EBAN-FRGZU)的变化;也可分析EBAN对象在CDHDR/CDPOS中的变更单据。 采集 监控EBAN发布状态字段的变更单据,以确定最终审批的时间戳。 事件类型 inferred | |||
| 采购订单已删除 | 表示取消或逻辑删除采购订单项目,使其无法继续收货或开票等处理。采购订单项目上的删除指示符被设置时,可推断此事件。 | ||
| 重要性 这是一个终止活动,表示订单已取消。分析订单删除的原因和时间,有助于发现需求计划或供应商选择方面的问题。 获取途径 根据变更单据(CDHDR/CDPOS)推断,查找采购订单项目的删除指示符(EKPO-LOEKZ)被设为“L”的记录。 采集 在变更单据中查找EKPO-LOEKZ标志被设置的时间戳。 事件类型 inferred | |||
| 采购订单已变更 | 表示采购订单创建后发生的任何修改,例如数量、价格或交货日期变更。这些变更会明确记录在SAP变更单据系统中。 | ||
| 重要性 频繁变更,尤其是审批后的变更,可能表明流程效率低、初始计划不充分或范围不断扩大。此活动是采购订单返工与变更仪表板及相关指标的必要数据。 获取途径 采购订单对象(EINKBELEG)的变更单据抬头表(CDHDR)和项目表(CDPOS)会明确记录每次变更,并生成带时间戳的新记录。 采集 从与采购订单编号关联的CDHDR和CDPOS表中提取变更事件及时间戳。 事件类型 explicit | |||
| 采购订单已拒绝 | 审批工作流中,审批人拒绝采购订单时会发生此活动。此事件根据采购订单发布策略数据中的状态变化推断,表明订单已被拒绝。 | ||
| 重要性 跟踪拒绝情况有助于发现采购订单数据质量问题、违反政策的情况或审批矩阵中的问题。订单被拒绝后通常需要返工,也会延长整体周期时间。 获取途径 根据采购订单发布状态的变更单据(CDHDR/CDPOS)推断。通常在发布代码被取消或设置特定拒绝状态时记录拒绝。 采集 监控变更日志,查找发布代码取消记录或表示拒绝的状态变化。 事件类型 inferred | |||
数据提取指南
步骤
- 创建ABAP程序:使用事务代码SE38打开ABAP编辑器。为新程序输入名称,例如Z_PM_PO_EXTRACT,然后点击“创建”。填写标题,例如“流程挖掘采购订单数据提取”,并将类型设为“可执行程序”。
- 定义选择屏幕:在程序中定义选择屏幕参数,供用户筛选要提取的数据。关键参数包括采购订单创建日期范围、公司代码(BUKRS)和采购凭证类型(BSART)。
- 定义数据结构:声明与最终事件日志格式一致的内部表结构。结构应包含所有必需和建议的属性:PurchaseOrder、Activity、EventTime、UserName、VendorNumber、OrderAmount、MaterialGroup、CompanyCode和DocumentType。
- 实现数据选择逻辑:编写核心ABAP逻辑,为14项必需活动分别选择数据。这需要查询多个SAP表,例如EKKO、EKPO、EKBE、EBAN、CDHDR、CDPOS和NAST。为每项活动使用单独的子例程(PERFORM),使代码结构清晰。
- 选择采购申请数据:查询EBAN表,获取“采购申请已创建”事件,并通过EKPO表将其关联到采购订单。使用变更日志表(CDHDR、CDPOS)跟踪发布状态字段的变化,以识别“采购申请已批准”事件。
- 选择采购订单核心事件:查询EKKO和EKPO表,获取“采购订单已创建”事件。针对对象EINKBELEG查询变更日志表(CDHDR、CDPOS),根据发布标识和删除标记等特定字段的变化,提取“采购订单已变更”“采购订单已批准”“采购订单已拒绝”“采购订单已完成”和“采购订单已删除”事件。
- 选择采购订单通信事件:查询NAST表,查找已成功发送采购订单的记录,记录“采购订单已发送给供应商”活动。
- 选择货物和服务事件:查询EKBE表中的物料凭证过账记录,根据移动类型类别识别“已过账收货”和“已退货”活动。查询ESSR和ESLL中的服务输入表,记录“已录入服务确认”活动。
- 选择质量管理事件:如果使用质量管理模块,查询QALS和QAVE表,识别与采购订单关联的检验批何时作出使用决策,并记录“已执行质量检验”活动。
- 合并并格式化数据:将各项选择结果汇总到一个最终内部表中。确保EventTime字段格式统一,例如YYYY-MM-DDTHH:MI:SS。
- 实现文件下载:添加将最终内部表下载为文件的功能。建议使用制表符分隔文件或CSV文件,可通过GUI_DOWNLOAD函数模块实现。
- 运行并保存:通过事务SE38或SA38运行程序。填写选择条件并执行报表。系统提示时,将输出文件以.csv扩展名保存到本地,以便上传。
配置
- 日期范围:提取时务必指定日期范围,通常依据采购订单创建日期(EKKO-AEDAT)设定。建议先选取3至6个月的数据,在数据量和流程洞察之间取得平衡。
- 公司代码(BUKRS):按一个或多个公司代码筛选,将提取范围限定在相关法人实体内。这是影响性能和分析相关性的关键参数。
- 采购凭证类型(BSART):按特定凭证类型筛选,例如“NB”代表标准采购订单,以聚焦标准流程;必要时可排除特殊采购类型。
- 数据粒度:提取以采购订单行项目为粒度。案例ID为采购订单号(EBELN)。包括收货在内的所有事件,即使发生在行项目层级,也会关联到此主案例ID。
- 性能注意事项:处理大型数据集时,请将程序安排为后台作业(SM36),以避免超时。确保WHERE子句使用的关键字段已建立数据库索引,尤其是CDHDR和CDPOS等表中的字段。
- 前提条件:运行报表的用户需要获得ABAP工作台(SE38)访问权限,以便开发程序,并具备程序执行权限。此外,还需要对所有相关表拥有读取权限,包括EKKO、EKPO、EKBE、CDHDR、CDPOS、EBAN、NAST、ESSR和QM表。
查询示例 abap
REPORT Z_PM_PO_EXTRACT.
TABLES: ekko, ekpo, eban.
*&---------------------------------------------------------------------*
*& Data Structures for Event Log
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
purchaseorder TYPE ebeln,
activity TYPE string,
eventtime TYPE timestamp,
username TYPE ernam,
vendornumber TYPE lifnr,
orderamount TYPE netwr_ak,
materialgroup TYPE matkl,
companycode TYPE bukrs,
documenttype TYPE bsart,
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_aedat FOR ekko-aedat OBLIGATORY, " PO Creation Date
s_bukrs FOR ekko-bukrs, " Company Code
s_bsart FOR ekko-bsart, " PO Document Type
s_ebeln FOR ekko-ebeln. " PO Number
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM get_po_headers.
IF gt_event_log IS NOT INITIAL.
PERFORM get_pr_created.
PERFORM get_pr_approved.
PERFORM get_po_created.
PERFORM get_po_release_events. " Approved, Rejected, Approval Requested
PERFORM get_po_sent_to_vendor.
PERFORM get_po_changed.
PERFORM get_goods_receipt_posted.
PERFORM get_services_confirmed.
PERFORM get_quality_inspection.
PERFORM get_goods_returned.
PERFORM get_po_completed.
PERFORM get_po_deleted.
PERFORM download_to_csv.
ELSE.
MESSAGE 'No Purchase Orders found for the given criteria.' TYPE 'I'.
ENDIF.
*&---------------------------------------------------------------------*
*& Form GET_PO_HEADERS (Base data)
*&---------------------------------------------------------------------*
FORM get_po_headers.
SELECT h~ebeln, h~lifnr, h~bukrs, h~bsart, p~netwr, p~matkl
FROM ekko AS h
INNER JOIN ekpo AS p ON h~ebeln = p~ebeln
INTO TABLE @DATA(lt_po_base)
WHERE h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND h~bsart IN @s_bsart
AND h~ebeln IN @s_ebeln.
SORT lt_po_base BY ebeln.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PR_CREATED
*&---------------------------------------------------------------------*
FORM get_pr_created.
DATA: lt_pr_events TYPE TABLE OF ty_event_log.
SELECT p~ebeln AS purchaseorder,
'Purchase Requisition Created' AS activity,
b~erdat AS event_date,
'000000' AS event_time,
b~ernam AS username,
h~lifnr AS vendornumber,
p~netwr AS orderamount,
p~matkl AS materialgroup,
h~bukrs AS companycode,
h~bsart AS documenttype
FROM ekpo AS p
JOIN eban AS b ON p~banfn = b~banfn AND p~bnfpo = b~bnfpo
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE p~ebeln IN @s_ebeln
AND p~banfn IS NOT NULL AND p~banfn <> ''
AND h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND h~bsart IN @s_bsart
INTO TABLE @DATA(lt_pr_created).
LOOP AT lt_pr_created ASSIGNING FIELD-SYMBOL(<fs_pr>).
DATA(ls_event) = CORRESPONDING ty_event_log(<fs_pr>).
CONCATENATE <fs_pr>-event_date <fs_pr>-event_time INTO DATA(lv_ts).
CONVERT DATE <fs_pr>-event_date TIME '000000' INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PR_APPROVED
*&---------------------------------------------------------------------*
FORM get_pr_approved.
DATA: lt_pr_list TYPE TABLE OF eban-banfn.
SELECT DISTINCT p~banfn FROM ekpo AS p
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND p~banfn IS NOT NULL AND p~banfn <> ''
INTO TABLE @lt_pr_list.
IF lt_pr_list IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime, p~fname, p~value_new
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectid = p~objectid AND h~changenr = p~changenr
FOR ALL ENTRIES IN @lt_pr_list
WHERE h~objectclas = 'BANF'
AND h~objectid = @lt_pr_list-table_line
AND p~tabname = 'EBAN'
AND p~fname = 'FRGZU'
INTO TABLE @DATA(lt_cd_pr).
LOOP AT lt_cd_pr ASSIGNING FIELD-SYMBOL(<fs_cd>) WHERE <fs_cd>-value_new = 'X'.
SELECT SINGLE p~ebeln, p~netwr, p~matkl, h~lifnr, h~bukrs, h~bsart
FROM ekpo AS p
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE p~banfn = @<fs_cd>-objectid(10)
INTO @DATA(ls_po_info).
IF sy-subrc = 0.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = ls_po_info-ebeln
activity = 'Purchase Requisition Approved'
username = <fs_cd>-username
vendornumber = ls_po_info-lifnr
orderamount = ls_po_info-netwr
materialgroup = ls_po_info-matkl
companycode = ls_po_info-bukrs
documenttype = ls_po_info-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_CREATED
*&---------------------------------------------------------------------*
FORM get_po_created.
LOOP AT lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>).
SELECT SINGLE aedat, ernam FROM ekko INTO @DATA(ls_ekko)
WHERE ebeln = @<fs_po>-ebeln.
IF sy-subrc = 0.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Created'
username = ls_ekko-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE ls_ekko-aedat TIME '000000' INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_RELEASE_EVENTS
*&---------------------------------------------------------------------*
FORM get_po_release_events.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime, p~value_new
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectid = p~objectid AND h~changenr = p~changenr
WHERE h~objectclas = 'EINKBELEG'
AND h~objectid IN lt_ebeln
AND p~tabname = 'EKKO'
AND p~fname = 'FRGKE'
INTO TABLE @DATA(lt_cd_po).
LOOP AT lt_cd_po ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
CASE <fs_cd>-value_new.
WHEN '2' OR 'R'. " Final Release
ls_event-activity = 'Purchase Order Approved'.
WHEN '1'. " Blocked
ls_event-activity = 'Purchase Order Rejected'.
WHEN OTHERS. " Any other change implies a pending state
ls_event-activity = 'Purchase Order Approval Requested'.
ENDCASE.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_SENT_TO_VENDOR
*&---------------------------------------------------------------------*
FORM get_po_sent_to_vendor.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT objky, erdat, eruhr, ernam
FROM nast
WHERE kapol = 'EF' AND objky IN lt_ebeln AND vstat = '1'
INTO TABLE @DATA(lt_nast).
LOOP AT lt_nast ASSIGNING FIELD-SYMBOL(<fs_nast>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_nast>-objky.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Sent to Vendor'
username = <fs_nast>-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_nast>-erdat TIME <fs_nast>-eruhr INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_CHANGED
*&---------------------------------------------------------------------*
FORM get_po_changed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT DISTINCT objectid, username, udate, utime
FROM cdhdr
WHERE objectclas = 'EINKBELEG' AND objectid IN lt_ebeln AND tcode <> 'ME21N' AND tcode <> 'ME22'
INTO TABLE @DATA(lt_cdhdr_chg).
LOOP AT lt_cdhdr_chg ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Changed'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_GOODS_RECEIPT_POSTED
*&---------------------------------------------------------------------*
FORM get_goods_receipt_posted.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT k~ebeln, m~cpudt, m~cputm, m~usnam, k~bewtp
FROM ekbe AS k JOIN mkpf AS m ON k~belnr = m~mblnr AND k~gjahr = m~mjahr
WHERE k~ebeln IN lt_ebeln AND k~bewtp = 'E' AND k~shkzg = 'S'
INTO TABLE @DATA(lt_gr).
LOOP AT lt_gr ASSIGNING FIELD-SYMBOL(<fs_gr>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_gr>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Goods Receipt Posted'
username = <fs_gr>-usnam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_gr>-cpudt TIME <fs_gr>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_SERVICES_CONFIRMED
*&---------------------------------------------------------------------*
FORM get_services_confirmed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT l~ebeln, h~erdat, h~eruhr, h~ernam
FROM essr AS h JOIN esll AS l ON h~lblni = l~lblni
WHERE l~ebeln IN lt_ebeln
INTO TABLE @DATA(lt_ses).
LOOP AT lt_ses ASSIGNING FIELD-SYMBOL(<fs_ses>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_ses>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Services Confirmation Entered'
username = <fs_ses>-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_ses>-erdat TIME <fs_ses>-eruhr INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_QUALITY_INSPECTION
*&---------------------------------------------------------------------*
FORM get_quality_inspection.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT q~ebeln, v~vdatum, v~vzeit, v~vname
FROM qals AS q JOIN qave AS v ON q~prueflos = v~prueflos
WHERE q~ebeln IN lt_ebeln
INTO TABLE @DATA(lt_qm).
LOOP AT lt_qm ASSIGNING FIELD-SYMBOL(<fs_qm>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_qm>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Quality Inspection Performed'
username = <fs_qm>-vname
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_qm>-vdatum TIME <fs_qm>-vzeit INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_GOODS_RETURNED
*&---------------------------------------------------------------------*
FORM get_goods_returned.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT k~ebeln, m~cpudt, m~cputm, m~usnam
FROM ekbe AS k JOIN mkpf AS m ON k~belnr = m~mblnr AND k~gjahr = m~mjahr
WHERE k~ebeln IN lt_ebeln AND k~bwart = '122'
INTO TABLE @DATA(lt_ret).
LOOP AT lt_ret ASSIGNING FIELD-SYMBOL(<fs_ret>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_ret>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Goods Returned'
username = <fs_ret>-usnam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_ret>-cpudt TIME <fs_ret>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_COMPLETED
*&---------------------------------------------------------------------*
FORM get_po_completed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime
FROM cdhdr AS h JOIN cdpos AS p ON h~changenr = p~changenr AND h~objectid = p~objectid
WHERE h~objectclas = 'EINKBELEG' AND h~objectid IN lt_ebeln AND p~tabname = 'EKPO' AND p~fname = 'ELIKZ' AND p~value_new = 'X'
INTO TABLE @DATA(lt_cd_comp).
LOOP AT lt_cd_comp ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Completed'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_DELETED
*&---------------------------------------------------------------------*
FORM get_po_deleted.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime
FROM cdhdr AS h JOIN cdpos AS p ON h~changenr = p~changenr AND h~objectid = p~objectid
WHERE h~objectclas = 'EINKBELEG' AND h~objectid IN lt_ebeln AND p~tabname = 'EKPO' AND p~fname = 'LOEKZ' AND p~value_new = 'L'
INTO TABLE @DATA(lt_cd_del).
LOOP AT lt_cd_del ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Deleted'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form DOWNLOAD_TO_CSV
*&---------------------------------------------------------------------*
FORM download_to_csv.
DATA: lv_filename TYPE string.
DATA: lt_fieldnames TYPE TABLE OF string.
APPEND 'PurchaseOrder' TO lt_fieldnames.
APPEND 'Activity' TO lt_fieldnames.
APPEND 'EventTime' TO lt_fieldnames.
APPEND 'UserName' TO lt_fieldnames.
APPEND 'VendorNumber' TO lt_fieldnames.
APPEND 'OrderAmount' TO lt_fieldnames.
APPEND 'MaterialGroup' TO lt_fieldnames.
APPEND 'CompanyCode' TO lt_fieldnames.
APPEND 'DocumentType' TO lt_fieldnames.
DATA(lv_header) = REDUCE string( INIT h = '' FOR f IN lt_fieldnames NEXT h = h && f && cl_abap_char_utilities=>horizontal_tab ).
REPLACE LAST OCCURRENCE OF cl_abap_char_utilities=>horizontal_tab IN lv_header WITH cl_abap_char_utilities=>cr_lf.
DATA(lv_file_content) = lv_header.
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_log>).
DATA lv_line TYPE string.
DATA lv_eventtime_str TYPE string.
lv_eventtime_str = |{ <fs_log>-eventtime TIMESTAMP = ISO }|.
lv_line = <fs_log>-purchaseorder && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-activity && cl_abap_char_utilities=>horizontal_tab &&
lv_eventtime_str && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-username && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-vendornumber && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-orderamount && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-materialgroup && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-companycode && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-documenttype && cl_abap_char_utilities=>cr_lf.
CONCATENATE lv_file_content lv_line INTO lv_file_content.
ENDLOOP.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = 'C:\temp\po_event_log.csv'
filetype = 'ASC'
CHANGING
data_tab = lv_file_content. 步骤
- 建立数据库连接:获取SAP ECC底层数据库的只读凭据和连接信息(主机名、端口、数据库名称)。确保已安装DBeaver、SQL Developer或SSMS等客户端工具。
- 识别SAP架构:连接数据库,确认存放相关表的主SAP架构。常见名称包括SAPSR3、SAPHANADB或其他系统专用名称。如果该架构不是用户的默认架构,查询中的所有表名都需要加上架构前缀。
- 检查SQL查询:在客户端工具中打开提供的SQL脚本。此查询通过联接多个SAP表,提取采购到付款流程中的14项不同活动。
- 自定义查询参数:找到脚本开头的PO_BASE公用表表达式(CTE),修改占位值以设定提取范围:
- [START_DATE]和[END_DATE]:设置分析日期范围,例如“20230101”和“20230630”。建议按AEDAT(变更日期)筛选。
- [COMPANY_CODE_1]、[COMPANY_CODE_2]:指定要纳入的SAP公司代码。
- [DOC_TYPE_1]、[DOC_TYPE_2]:指定要纳入的采购订单凭证类型。
- [Your SAP Schema]:在脚本中将此占位符替换为实际的SAP架构名称。
- 执行查询:在SAP数据库中运行自定义SQL脚本。执行时间取决于日期范围、数据量和数据库性能。
- 检查结果:查询完成后,快速检查输出结果。确认行数合理,并确保PurchaseOrder、Activity和EventTime等关键列已按预期填充。
- 将数据导出为CSV:使用SQL客户端将完整结果集导出为CSV文件。请使用UTF-8编码,避免字符显示异常。
- 准备上传:确保CSV文件中的列标题与所需属性名称完全一致:PurchaseOrder、Activity、EventTime、UserName、VendorNumber、OrderAmount、MaterialGroup、CompanyCode、DocumentType。
- 上传到流程挖掘工具:将最终CSV文件上传到您的流程挖掘应用程序,以进行分析和可视化。
配置
- 前提条件:需要对SAP ECC底层数据库拥有直接只读访问权限。用户必须具备查询EKKO、EKPO、EKBE、EBAN、CDHDR、CDPOS和NAST等表的相应权限。
- 日期范围筛选:务必使用日期范围筛选,以控制数据量。通常可先按EKKO.AEDAT(采购订单变更日期)筛选3至6个月的数据。日期范围过大可能导致查询执行时间过长。
- 关键数据筛选:为确保分析聚焦,请始终按EKKO.BUKRS(公司代码)和EKKO.BSART(凭证类型)筛选,将范围限定在相关法人实体和业务流程内。
- 性能注意事项:查询需要联接多个大型表,包括变更历史表(CDHDR、CDPOS),可能占用大量资源。强烈建议在非高峰时段运行提取,或改用复制的非生产数据库,以免影响系统性能。
- 变更凭证日志:“已批准”“已拒绝”“已完成”和“已变更”等活动的准确性取决于SAP中相关字段是否启用了变更凭证日志。请与SAP管理员确认是否已通过事务SCDO启用日志记录。
查询示例 sql
WITH PO_BASE AS (
SELECT
H.EBELN, -- Purchase Order Number
I.EBELP, -- Purchase Order Item
H.LIFNR, -- Vendor Number
H.BUKRS, -- Company Code
H.BSART, -- Document Type
I.NETWR, -- Order Amount (Item Level)
I.MATKL, -- Material Group
I.BANFN, -- Purchase Requisition Number
I.BNFPO -- Purchase Requisition Item
FROM [Your SAP Schema].EKKO AS H
JOIN [Your SAP Schema].EKPO AS I ON H.EBELN = I.EBELN
WHERE H.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' -- Filter on PO Change Date, e.g., '20230101' and '20231231'
AND H.BUKRS IN ('[COMPANY_CODE_1]', '[COMPANY_CODE_2]') -- Specify Company Codes
AND H.BSART IN ('[DOC_TYPE_1]', '[DOC_TYPE_2]') -- Specify PO Document Types
)
-- 1. Purchase Requisition Created
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Requisition Created' AS "Activity",
TO_TIMESTAMP(CONCAT(pr.ERDAT, '000000'), 'YYYYMMDDHH24MISS') AS "EventTime", -- Time is not available in EBAN
pr.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EBAN pr ON po.BANFN = pr.BANFN AND po.BNFPO = pr.BNFPO
WHERE po.BANFN IS NOT NULL AND po.BANFN <> ''
UNION ALL
-- 2. Purchase Requisition Approved
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Requisition Approved' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'BANF' AND ch.OBJECTID = po.BANFN
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EBAN' AND cp.FNAME = 'FRGZU' AND cp.VALUE_NEW = 'X' -- Release indicator set to 'released'
UNION ALL
-- 3. Purchase Order Created
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Created' AS "Activity",
TO_TIMESTAMP(CONCAT(ekko.ERDAT, ' ', ekko.ERZET), 'YYYYMMDD HH24MISS') AS "EventTime",
ekko.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKKO ekko ON po.EBELN = ekko.EBELN
UNION ALL
-- 4. Purchase Order Approval Requested / 5. Approved / 6. Rejected (from Change Docs)
SELECT
po.EBELN AS "PurchaseOrder",
CASE
WHEN cp.VALUE_NEW > cp.VALUE_OLD THEN 'Purchase Order Approval Requested'
WHEN cp.VALUE_NEW = ekko.FRGKE AND ekko.FRGKE = 'R' THEN 'Purchase Order Approved'
ELSE 'Purchase Order Rejected' -- Simplified logic, may need adjustment
END AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKKO ekko ON po.EBELN = ekko.EBELN
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID = po.EBELN
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKKO' AND cp.FNAME = 'FRGZU' -- Release status
UNION ALL
-- 7. Purchase Order Sent to Vendor
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Sent to Vendor' AS "Activity",
TO_TIMESTAMP(CONCAT(na.ERDAT, ' ', na.ERUHR), 'YYYYMMDD HH24MISS') AS "EventTime",
na.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].NAST na ON na.OBJKY = po.EBELN AND na.KSCHL = '[Your PO Output Type]' -- e.g., 'NEU'
WHERE na.VSTAT = '1' -- Successfully processed
UNION ALL
-- 8. Purchase Order Changed
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Changed' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID = po.EBELN
WHERE ch.TCODE IN ('ME22', 'ME22N') -- Filter for change transactions
UNION ALL
-- 9. Goods Receipt Posted
SELECT
ekbe.EBELN AS "PurchaseOrder",
'Goods Receipt Posted' AS "Activity",
TO_TIMESTAMP(CONCAT(mkpf.CPUDT, ' ', mkpf.CPUTM), 'YYYYMMDD HH24MISS') AS "EventTime",
mkpf.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM [Your SAP Schema].EKBE AS ekbe
JOIN [Your SAP Schema].MKPF AS mkpf ON ekbe.BELNR = mkpf.MBLNR AND ekbe.GJAHR = mkpf.MJAHR
JOIN PO_BASE AS po ON ekbe.EBELN = po.EBELN AND ekbe.EBELP = po.EBELP
WHERE ekbe.BEWTP = 'E' -- Goods Receipt
AND ekbe.SHKZG = 'S' -- Debit/Credit Indicator: Goods Receipt
UNION ALL
-- 10. Services Confirmation Entered
SELECT
po.EBELN AS "PurchaseOrder",
'Services Confirmation Entered' AS "Activity",
TO_TIMESTAMP(CONCAT(essr.ERDAT, ' ', essr.ERZET), 'YYYYMMDD HH24MISS') AS "EventTime",
essr.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKBE ekbe ON po.EBELN = ekbe.EBELN AND po.EBELP = ekbe.EBELP
JOIN [Your SAP Schema].ESSR essr ON ekbe.LBLNI = essr.LBLNI
WHERE ekbe.BEWTP = 'L' -- Service Entry Sheet
UNION ALL
-- 11. Quality Inspection Performed
SELECT
po.EBELN AS "PurchaseOrder",
'Quality Inspection Performed' AS "Activity",
TO_TIMESTAMP(CONCAT(qave.VDATUM, ' ', qave.VZEIT), 'YYYYMMDD HH24MISS') AS "EventTime",
qave.VNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKBE ekbe ON po.EBELN = ekbe.EBELN AND po.EBELP = ekbe.EBELP
JOIN [Your SAP Schema].QALS qals ON qals.MBLNR = ekbe.BELNR AND qals.MJAHR = ekbe.GJAHR
JOIN [Your SAP Schema].QAVE qave ON qals.PRUEFLOS = qave.PRUEFLOS
WHERE ekbe.BEWTP = 'E' -- Linked to a Goods Receipt
UNION ALL
-- 12. Goods Returned
SELECT
ekbe.EBELN AS "PurchaseOrder",
'Goods Returned' AS "Activity",
TO_TIMESTAMP(CONCAT(mkpf.CPUDT, ' ', mkpf.CPUTM), 'YYYYMMDD HH24MISS') AS "EventTime",
mkpf.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM [Your SAP Schema].EKBE AS ekbe
JOIN [Your SAP Schema].MKPF AS mkpf ON ekbe.BELNR = mkpf.MBLNR AND ekbe.GJAHR = mkpf.MJAHR
JOIN PO_BASE AS po ON ekbe.EBELN = po.EBELN AND ekbe.EBELP = po.EBELP
WHERE ekbe.BEWTP = 'E' -- Goods Movement
AND ekbe.SHKZG = 'H' -- Debit/Credit Indicator: Return
AND ekbe.BWART = '122' -- Movement type for return to vendor
UNION ALL
-- 13. Purchase Order Completed
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Completed' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID LIKE CONCAT(po.EBELN, po.EBELP, '%')
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKPO' AND cp.FNAME = 'ELIKZ' AND cp.VALUE_NEW = 'X' -- Delivery completed indicator
UNION ALL
-- 14. Purchase Order Deleted
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Deleted' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID LIKE CONCAT(po.EBELN, po.EBELP, '%')
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKPO' AND cp.FNAME = 'LOEKZ' AND cp.VALUE_NEW = 'L'; -- Deletion indicator 步骤
- 前提条件和连接:确保第三方ETL工具已安装并获得SAP认证连接器许可。在ETL工具的管理控制台中配置与SAP ECC系统的新连接。您需要提供应用服务器主机、系统编号、客户端ID,以及具备相应RFC权限和表读取权限的专用SAP用户。
- 识别源表:在ETL作业或数据流中,将所需SAP表定义为数据源。主要包括EKKO(采购订单抬头)、EKPO(采购订单行项目)、EBAN(采购申请)、CDHDR(变更凭证抬头)、CDPOS(变更凭证项目)、MSEG(物料凭证项目)、MKPF(物料凭证抬头)、NAST(消息状态)、ESSR(服务输入表抬头)和QALS(检验批)。
- 提取“采购订单已创建”事件:创建一个以EKKO表为数据源的数据流。按所需日期范围(例如使用AEDAT)和组织范围(例如使用BUKRS筛选公司代码、使用BSART筛选凭证类型)筛选记录。将EKKO.EBELN映射到PurchaseOrder,将“采购订单已创建”映射到Activity,并合并AEDAT和ERZET作为EventTime。映射其他必需属性。
- 提取“已过账收货”事件:创建一个以MSEG为数据源并通过MBLNR和MJAHR与MKPF联接的独立数据流。筛选相关移动类型,例如“101”。将MSEG.EBELN映射到PurchaseOrder,将“已过账收货”映射到Activity,并使用MKPF.CPUDT和MKPF.CPUTM作为EventTime。
- 提取基于变更的事件(审批、变更、删除):创建一个数据流,将CDHDR和CDPOS作为数据源并通过CHANGENR联接。此数据源可用于推导多项活动。
- 筛选OBJECTCLAS = 'EINKBELEG'和TABNAME = 'EKPO'。
- 对于**“采购订单已批准”**,筛选发布状态字段的变更,例如FNAME = 'FRGZU',其中新值(VALUE_NEW)表示最终审批已完成。
- 对于**“采购订单已删除”**,筛选删除标记的变更(FNAME = 'LOEKZ'),且新值为'L'。
- 对于**“采购订单已变更”**,筛选其他相关字段的变更,并排除用于其他活动的特定状态字段。
- 对于以上所有事件,使用CDHDR.UDATE和CDHDR.UTIME作为EventTime。
- 提取“采购申请”事件:从EBAN创建数据流,提取“采购申请已创建”事件。若要将其关联到采购订单案例,请使用申请编号(BANFN)和项目(BNFPO)将EBAN与EKPO联接。要提取“采购申请已批准”事件,请使用OBJECTCLAS = 'BANF'的CDHDR/CDPOS数据。需要仔细映射,确保事件关联到最终生成的采购订单。
- 提取“采购订单已发送给供应商”事件:创建一个以NAST表为数据源的数据流。按OBJECTKEY(包含采购订单号)、相关输出类型(KSCHL)和成功处理状态(VSTAT = '1')筛选。使用ERDAT和UHR作为EventTime。
- 合并活动数据流:使用ETL工具中的“Union”或“Merge”转换,合并前述步骤创建的各个数据流输出。确保所有数据流的列名和数据类型一致,例如PurchaseOrder、Activity和EventTime。
- 转换数据类型和格式:确保EventTime列转换为统一的时间戳格式,例如YYYY-MM-DD HH:MM:SS。将OrderAmount转换为标准十进制格式。
- 定义目标位置:为合并后的数据流配置目标或“接收端”。通常使用CSV或Parquet等扁平文件,并配置分隔符、文本限定符和标题选项。
- 运行并验证:运行完整ETL作业。检查输出文件,确认14项活动均已包含、行数合理,且关键属性已正确填充。
- 安排并导出:验证完成后,安排ETL作业定期运行,例如每晚运行,以保持数据更新。生成的文件即可上传到流程挖掘工具。
配置
- 前提条件:使用商业ETL工具(如Informatica PowerCenter、Talend、SAP Data Services),并配备适用于ECC的相应SAP认证连接器。还需要具有S_RFC和S_TABU_DIS权限(针对所需表)的SAP对话用户或系统用户。
- SAP连接:连接器必须配置SAP应用服务器、系统编号、客户端、用户名和密码。建议使用安全网络通信(SNC)。
- 日期范围筛选:必须设置日期范围筛选,以限制数据量。常见做法是筛选EKKO.AEDAT(采购订单创建日期),提取最近3至12个月的数据。应在数据源端应用此筛选,避免从SAP提取过多数据。
- 组织范围筛选:始终按EKKO.BUKRS(公司代码)筛选,并考虑按EKPO.WERKS(工厂)或EKKO.EKORG(采购组织)筛选,将分析范围缩小到特定业务单元。
- 单据类型筛选:使用EKKO.BSART仅纳入相关采购订单类型,并排除库存调拨或其他不属于标准采购到付款流程的内部单据。
- 性能调优:从更改单据表(CDHDR、CDPOS)提取数据可能较慢。请确保对OBJECTCLAS、OBJECTID和UDATE应用筛选。调整SAP连接器中的“Packet Size”设置,以优化数据传输速率。对于规模很大的系统,可考虑先进行一次历史数据加载,再按计划增量加载。
查询示例 sql
/*
This is a logical representation of the transformations performed within the ETL tool.
The tool's graphical interface will be used to configure these separate data flows, which are then combined with a UNION transformation.
Placeholders like [Your ETL Tool Functions] and [Filter Values] must be configured in the tool.
*/
-- 1. Purchase Requisition Created
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Requisition Created' AS Activity,
[Your ETL Tool Functions].DateTime(eban.ERDAT, eban.ERZET) AS EventTime,
eban.ERNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM EBAN AS eban
INNER JOIN EKPO AS ekpo ON eban.BANFN = ekpo.BANFN AND eban.BNFPO = ekpo.BNFPO
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 2. Purchase Requisition Approved (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Requisition Approved' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EBAN AS eban ON cdhdr.OBJECTID = eban.BANFN
INNER JOIN EKPO AS ekpo ON eban.BANFN = ekpo.BANFN AND eban.BNFPO = ekpo.BNFPO
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'BANF' AND cdpos.TABNAME = 'EBAN' AND cdpos.FNAME = 'FRGZU' AND cdpos.VALUE_NEW = '[Final Release Indicator for PR]'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 3. Purchase Order Created
SELECT
EBELN AS PurchaseOrder,
'Purchase Order Created' AS Activity,
[Your ETL Tool Functions].DateTime(AEDAT, ERZET) AS EventTime,
ERNAM AS UserName,
LIFNR AS VendorNumber,
NULL AS OrderAmount, -- Amount is at item level
NULL AS MaterialGroup, -- Attribute is at item level
BUKRS AS CompanyCode,
BSART AS DocumentType
FROM EKKO
WHERE AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 4. Purchase Order Approval Requested / 5. Approved / 6. Rejected (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
CASE
WHEN cdpos.VALUE_NEW = '[Final Release Code]' THEN 'Purchase Order Approved'
WHEN cdpos.VALUE_NEW = '[Rejection Release Code]' THEN 'Purchase Order Rejected'
ELSE 'Purchase Order Approval Requested'
END AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKKO AS ekko ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKKO' AND cdpos.FNAME = 'FRGKE'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 7. Purchase Order Sent to Vendor
SELECT
ekko.EBELN AS PurchaseOrder,
'Purchase Order Sent to Vendor' AS Activity,
[Your ETL Tool Functions].DateTime(nast.ERDAT, nast.UHR) AS EventTime,
nast.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM NAST AS nast
INNER JOIN EKKO AS ekko ON nast.OBJKY = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE nast.KAPPL = 'EF' AND nast.VSTAT = '1' AND nast.KSCHL IN ([Your PO Output Types])
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 8. Purchase Order Changed (inferred from change documents, simplified example)
SELECT DISTINCT
ekko.EBELN AS PurchaseOrder,
'Purchase Order Changed' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKKO AS ekko ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.FNAME NOT IN ('FRGKE', 'FRGZU', 'LOEKZ', 'ELIKZ')
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 9. Goods Receipt Posted
SELECT
mseg.EBELN AS PurchaseOrder,
'Goods Receipt Posted' AS Activity,
[Your ETL Tool Functions].DateTime(mkpf.CPUDT, mkpf.CPUTM) AS EventTime,
mkpf.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM MSEG AS mseg
INNER JOIN MKPF AS mkpf ON mseg.MBLNR = mkpf.MBLNR AND mseg.MJAHR = mkpf.MJAHR
INNER JOIN EKPO AS ekpo ON mseg.EBELN = ekpo.EBELN AND mseg.EBELP = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE mseg.BWART = '101' AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 10. Services Confirmation Entered
SELECT
essr.EBELN AS PurchaseOrder,
'Services Confirmation Entered' AS Activity,
[Your ETL Tool Functions].DateTime(essr.ERDAT, essr.ERZET) AS EventTime,
essr.ERNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM ESSR AS essr
INNER JOIN EKKO AS ekko ON essr.EBELN = ekko.EBELN
INNER JOIN EKPO AS ekpo ON essr.EBELN = ekpo.EBELN AND essr.EBELP = ekpo.EBELP
WHERE ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 11. Quality Inspection Performed
SELECT
qals.EBELN AS PurchaseOrder,
'Quality Inspection Performed' AS Activity,
[Your ETL Tool Functions].DateTime(qals.PASTRTERM, '000000') AS EventTime, -- Time is often not available
qals.PRUEFER AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM QALS AS qals
INNER JOIN EKKO AS ekko ON qals.EBELN = ekko.EBELN
INNER JOIN EKPO AS ekpo ON qals.EBELN = ekpo.EBELN AND qals.EBELP = ekpo.EBELP
WHERE qals.VCODE <> '' -- A usage decision code exists
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 12. Goods Returned
SELECT
mseg.EBELN AS PurchaseOrder,
'Goods Returned' AS Activity,
[Your ETL Tool Functions].DateTime(mkpf.CPUDT, mkpf.CPUTM) AS EventTime,
mkpf.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM MSEG AS mseg
INNER JOIN MKPF AS mkpf ON mseg.MBLNR = mkpf.MBLNR AND mseg.MJAHR = mkpf.MJAHR
INNER JOIN EKPO AS ekpo ON mseg.EBELN = ekpo.EBELN AND mseg.EBELP = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE mseg.BWART = '122' AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 13. Purchase Order Completed (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Order Completed' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKPO AS ekpo ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekpo.EBELN AND SUBSTRING(cdhdr.OBJECTID, 11, 5) = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKPO' AND cdpos.FNAME = 'ELIKZ' AND cdpos.VALUE_NEW = 'X'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 14. Purchase Order Deleted (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Order Deleted' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKPO AS ekpo ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekpo.EBELN AND SUBSTRING(cdhdr.OBJECTID, 11, 5) = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKPO' AND cdpos.FNAME = 'LOEKZ' AND cdpos.VALUE_NEW = 'L'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]); 优化采购到付款流程中的采购订单:立即开始免费试用
消除瓶颈,将周期时间缩短30%或以上。
无需信用卡,几分钟即可开始