您的采购到付款流程:采购订单数据模板
您的采购到付款流程:采购订单数据模板
- 建议收集的属性
- 需要跟踪的关键活动
- SAP ECC数据提取指南
采购到付款-采购订单属性
| 名称 | 说明 | ||
|---|---|---|---|
| 事件时间 EventTime | 活动发生的准确日期和时间。 | ||
| 说明 此时间戳标记事件发生的准确时刻,例如PO获批或收货过账的时间,并确定案例中所有活动的时间顺序。 时间戳是流程挖掘的基础,因为所有基于时间的分析都依赖于它,包括计算活动间周期时间、识别延迟、分析流程吞吐量以及根据服务级别协议(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、记录GR/IR的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 | 采购订单项目的货币总价值。 | ||
| 说明 此属性表示采购订单中特定项目的总价值,按数量乘以净价计算。要获得完整PO价值,需要汇总各项目金额。 按订单金额分析流程,对于识别需要更严格控制或不同审批路径的高价值交易至关重要。它支持“采购订单价值分析”仪表板,并帮助优先改进财务影响最大的订单流程。 为什么重要 量化每次采购的财务影响,支持基于价值的分析,从而优先处理高价值订单或识别节省成本的机会。 获取位置 表:EKPO,字段:NETWR(订单净值)。 示例 1500.00250.7512345.50 | |||
| 上次数据更新 LastDataUpdate | 表示数据最近一次从源系统刷新时间的时间戳。 | ||
| 说明 此属性记录最近一次数据提取或更新的日期和时间,帮助了解当前分析数据的新鲜度。 在仪表板中显示此信息,有助于用户判断洞察基于近实时数据还是历史快照,明确数据时效并确保决策基于已知时间范围内的数据。 为什么重要 告知用户数据的时效性,确保用户了解分析是否反映运营的最新状态。 获取位置 此时间戳由数据提取或ETL流程在执行时生成并添加。 示例 2023-10-27T02:00:00Z2023-10-28T02:00:00Z | |||
| 供应商名称 VendorName | 供应商的法定名称。 | ||
| 说明 供应商的描述性名称,比供应商编号更便于用户理解,通常取自供应商主数据。 供应商编号用于关联和唯一标识,而供应商名称对于面向用户的仪表板和报告至关重要,可让不熟悉供应商代码的业务用户更直观地理解分析结果。 为什么重要 提供易于理解的供应商名称,让业务用户更容易看懂仪表板和报告。 获取位置 表:LFA1,字段:NAME1。需要将EKKO-LIFNR与LFA1-LIFNR关联。 示例 Staples Inc.Global Tech SolutionsOffice Supply Co. | |||
| 工厂 Plant | 货物交付地点或工厂的实际位置。 | ||
| 说明 工厂是代表生产设施、仓库或其他货物和服务接收地点的组织单位。 按工厂分析有助于了解采购流程的地域差异,发现不同地点的供应商交付时间差异,或识别收货流程低效的具体工厂,从而支持收货及时性分析。 为什么重要 指定交付地点,可用于分析区域流程差异和物流绩效。 获取位置 表:EKPO,字段:WERKS 示例 100011002000 | |||
| 拒绝原因 RejectionReason | 用于说明采购申请或采购订单为何被拒绝的原因代码或文本。 | ||
| 说明 此属性记录采购订单在审批工作流中被拒绝时提供的具体原因。这些信息对于了解返工和延误的根本原因至关重要。 分析拒绝原因有助于识别定价错误、预算超支或供应商选择不合规等常见问题。借助这些洞察,企业可以解决根本原因,提高采购订单初始创建质量,并简化审批流程。 为什么重要 直接揭示审批失败的原因,帮助企业采取针对性改进措施,减少返工并缩短审批周期。 获取位置 这类信息可能难以定位,可能存储在长文本字段中,或取决于自定义工作流配置。通常需要具备特定的实施知识。 示例 价格错误超出预算重复申请 | |||
| 是否为审批后变更 IsPostApprovalChange | 用于标记初始审批后是否发生过采购订单变更。 | ||
| 说明 如果同一采购订单在检测到“Purchase Order Approved”活动后又检测到“Purchase Order Changed”活动,则此布尔属性为true。它有助于定位流程后期发生的问题变更。 此计算字段直接支持“Post-Approval PO Change Rate”KPI和“Purchase Order Rework and Changes”仪表板。它有助于量化并突出可能导致延误、需要重新审批的干扰性变更,从而指向初始规格定义或范围界定中的问题。 为什么重要 直接衡量审批后的返工情况,是评估流程稳定性和效率的关键KPI。比率较高通常表明上游需求定义存在问题。 获取位置 这是根据事件日志中的活动顺序计算得出的属性。 示例 truefalse | |||
| 是否按时交付 IsOnTimeDelivery | 用于标记货物是否在要求的交付日期当天或之前收到。 | ||
| 说明 如果“Goods Receipt Posted”活动的时间戳早于或等于“Requested Delivery Date”,则此布尔属性为true。它为每个采购订单行项目提供清晰的二元交付绩效结果。 此属性是“On-Time Goods Receipt Rate”KPI的基础。通过便于汇总和筛选按时交付与延迟交付的数据,它简化了供应商绩效和内部收货效率分析。 为什么重要 为交付及时性提供清晰的成功或失败指标,直接支持供应商绩效KPI和仪表板。 获取位置 这是通过比较收货过账日期(EKBE-BUDAT)与要求的交付日期(EKPO-EINDT)计算得出的属性。 示例 truefalse | |||
| 源系统 SourceSystem | 提取数据的系统。 | ||
| 说明 此属性标识数据来源,通常是SAP ECC实例标识符,例如“ECC_PROD_100”。在多系统环境中,它有助于区分不同数据源。 对于治理和数据血缘,了解源系统至关重要。它有助于确保数据完整性,并排查数据提取或质量问题,尤其是在合并不同ERP系统或模块的数据时。 为什么重要 标识数据来源,对于数据治理、验证以及管理跨多个系统的分析至关重要。 获取位置 通常是在数据提取过程中添加的静态值,用于标记数据集的来源系统。 示例 SAP_ECC_PRODECC_EU_100S4H_FIN | |||
| 要求交付日期 RequestedDeliveryDate | 业务方向供应商要求交付货物或服务的日期。 | ||
| 说明 这是采购订单中指定的目标交付日期,也是衡量实际交付绩效的基准。 该日期对于计算“按时收货率”KPI至关重要。通过将实际收货日期与要求交付日期进行比较,组织可以量化评估供应商可靠性和内部收货效率,并为“供应商交付绩效”仪表板提供依据。 为什么重要 这是交付目标日期,对于计算按时交付绩效KPI和评估供应商可靠性至关重要。 获取位置 表:EKPO,字段:EINDT 示例 2023-06-102023-07-222023-08-01 | |||
| 货币 Currency | 采购订单金额使用的货币代码。 | ||
| 说明 此属性指定采购订单价值的计价货币,例如USD、EUR或GBP,为所有金额提供必要背景。 对于全球化组织,货币是准确开展财务分析的基础。它支持正确汇总和比较订单价值,所有货币类KPI都必须结合相应货币进行解读。 为什么重要 为所有金额提供必要背景,确保财务分析准确,尤其适用于跨国组织。 获取位置 表:EKKO,字段:WAERS 示例 USDEURJPY | |||
| 采购申请 PurchaseRequisition | 采购订单之前采购申请的标识符。 | ||
| 说明 此属性将采购订单关联回其来源采购申请。并非所有PO都有前置采购申请。 该关联对于分析“申请到订单转换”仪表板和“PR到PO转换率”KPI至关重要。它支持衡量从初始申请到正式订单创建的上游流程效率,并识别未经过采购申请直接创建的不合规PO。 为什么重要 将PO关联到来源申请,支持分析PR到PO转换流程,并识别未经过前置采购申请直接创建的PO。 获取位置 表:EKPO,字段:BANFN 示例 1001589010015891 | |||
| 采购组 PurchasingGroup | 负责采购活动的具体采购员或采购员团队。 | ||
| 说明 采购组代表负责某项采购活动的采购员或团队,是供应商的主要联系人。 该属性提供比采购组织更细粒度的分析视角,有助于了解采购员之间的工作量分配和绩效差异,为资源配置和培训提供依据。 为什么重要 以更细粒度展示采购负责人,支持在采购员或团队层面详细分析工作量和绩效。 获取位置 表:EKKO,字段:EKGRP 示例 001002N01 | |||
| 采购组织 PurchasingOrganization | 负责协商价格以及采购物料或服务的组织单位。 | ||
| 说明 采购组织是SAP中负责采购活动的关键组织单位,可以覆盖整个公司的集中式组织,也可以按工厂或区域分散设置。 按采购组织分析流程绩效,有助于识别效率最高的采购团队,并比较不同组织单位的周期时间、返工率和成本,发现最佳实践及需要支持的领域。 为什么重要 标识负责采购的团队,支持比较不同组织单位的绩效并开展分析。 获取位置 表:EKKO,字段:EKORG 示例 1000US01DE01 | |||
采购到付款-采购订单活动
| 活动 | 说明 | ||
|---|---|---|---|
| 创建采购申请 | 此活动表示正式的货物或服务申请已创建。当用户保存新的采购申请单据时,会记录这一明确事件,例如使用ME51N等事务码,并在EBAN表中生成唯一记录。 | ||
| 为什么重要 这是采购流程的主要起点。分析从该事件到采购订单创建之间的时间,有助于衡量将内部需求转化为可执行订单的效率。 获取位置 在采购申请抬头表EBAN中创建条目时记录。EBAN-BADAT中的创建日期和时间作为该事件的时间戳。 采集 根据创建日期识别EBAN表中的新条目。 事件类型 explicit | |||
| 创建采购订单 | 此活动表示正式采购订单单据已创建,该单据构成与供应商之间具有约束力的合同。当用户创建并保存PO时会记录这一明确事件,例如通过ME21N事务码操作,并在EKKO和EKPO表中生成条目。 | ||
| 为什么重要 标志着采购订单生命周期正式开始。这是衡量PR到PO转换时间以及端到端订单履行时间的关键里程碑。 获取位置 从采购订单抬头表EKKO中对应PO编号EKKO-EBELN的创建日期EKKO-AEDAT获取。 采集 使用EKKO表中每个新采购订单的创建时间戳。 事件类型 explicit | |||
| 已过账收货 | 此活动表示已根据特定采购订单实际收到供应商交付的货物。过账收货是明确执行的操作,例如通过MIGO事务码完成,会创建物料凭证并更新库存。 | ||
| 为什么重要 这是跟踪供应商交付绩效以及发票校验流程开始的关键里程碑,可用于计算按时交付率和收货及时性。 获取位置 在创建物料凭证时记录。事件时间戳取自物料凭证抬头表MKPF中的过账日期MKPF-BUDAT或创建日期MKPF-CPUDT,并通过项目表MSEG与PO关联。 采集 使用MKPF表中引用该PO的物料凭证的过账或创建时间戳。 事件类型 explicit | |||
| 采购订单已发送给供应商 | 此活动标志着已批准的采购订单正式传输给供应商,例如通过EDI、电子邮件或打印方式发送。当输出消息成功处理时,会在消息控制表中记录这一明确事件。 | ||
| 为什么重要 这是供应商交付周期开始计时的关键里程碑。分析从该事件到收货之间的时间,是评估供应商绩效和交付及时性的关键。 获取位置 记录在消息状态表NAST中。当相关PO输出类型的处理状态NAST-VSTAT为“1”(处理成功)时,可从NAST-DATVR和NAST-UHRVR获取时间戳。 采集 使用NAST表中PO输出消息的处理时间戳。 事件类型 explicit | |||
| 采购订单已完成 | 表示采购订单项目已视为全部交付。这是一个推断事件,通常根据采购订单项目上的“交付完成”指示器被自动或手动设置来确定。 | ||
| 为什么重要 此活动是订单履行流程的逻辑终点,对于计算从创建到完成的端到端PO周期时间至关重要。 获取位置 根据变更凭证CDHDR/CDPOS推断,这些记录显示采购订单项目的“交付完成”指示器EKPO-ELIKZ被设置为“X”。最后一个项目标记完成时,可视为整个PO完成。 采集 从变更凭证中识别EKPO-ELIKZ标志被设置时的时间戳。 事件类型 inferred | |||
| 采购订单已批准 | 表示采购订单已获得最终批准,可以发送给供应商。通常根据PO发布状态变更为“完全发布”或“已批准”状态来推断这一关键里程碑。 | ||
| 为什么重要 此活动对于计算PO审批周期时间KPI、识别审批工作流中的瓶颈至关重要,也是向供应商发送订单等后续活动的前提。 获取位置 通过跟踪采购订单抬头表EKKO的变更日志CDHDR/CDPOS推断,查找最终发布代码的应用时间,或整体发布状态指示器EKKO-FRGKE被设置为“已发布”的时间。 采集 识别PO整体发布状态EKKO-FRGKE变更为最终批准状态的时间戳。 事件类型 inferred | |||
| 已录入服务确认 | 对于服务类采购订单,此活动表示服务已完成并得到确认。当创建服务条目表时会记录这一明确事件,例如通过ML81N事务码操作。 | ||
| 为什么重要 这相当于服务采购中的收货,是跟踪服务订单履行情况的必要环节,并会触发服务付款的财务流程。 获取位置 从服务条目表抬头表ESSR中的创建日期ESSR-ERDAT获取。采购订单与ESSR的关联位于ESLL表中。 采集 使用与PO关联的服务条目表在ESSR表中的创建时间戳。 事件类型 explicit | |||
| 已执行质量检验 | 表示收到的货物已完成质量检验。通常在收货时创建的检验批在质量管理模块中做出使用决策后,推断出该活动。 | ||
| 为什么重要 对于质量要求较高的行业,此活动有助于分析检验流程的持续时间和结果。此处的延迟可能在收货与货物可用之间形成瓶颈。 获取位置 根据质量管理模块推断。收货时会在QALS表中创建检验批,创建使用决策时标记该活动,相关记录位于QAVE表并包含时间戳。 采集 识别QAVE表中与物料凭证关联的检验批的使用决策时间戳。 事件类型 inferred | |||
| 已请求采购订单审批 | 表示已创建或变更的采购订单已根据配置的发布策略提交审批。当发布策略被触发且PO进入待审批状态时,可推断出该事件。 | ||
| 为什么重要 区分PO创建与审批流程开始,有助于准确衡量审批周期时间KPI,也能突出审批工作流启动前的延迟。 获取位置 根据采购订单对象EINKBELEG的变更凭证CDHDR/CDPOS推断,相关记录显示发布状态的初始设置;也可在整体发布状态EKKO-FRGKE首次设置为表示审批流程已启动的值时识别。 采集 识别触发PO发布策略的第一条变更凭证记录。 事件类型 inferred | |||
| 货物已退回 | 表示将之前收到的货物退回供应商,通常原因是质量问题或发货错误。这是一个明确事件,在使用退货专用移动类型过账物料凭证时记录。 | ||
| 为什么重要 此活动反映供应商质量或订单准确性问题,是流程返工的重要指标,也是计算收货差异率KPI的关键。 获取位置 当使用退货移动类型时,记录在物料凭证表MKPF/MSEG中,例如“122”(退回供应商)。过账日期MKPF-BUDAT作为时间戳。 采集 识别使用退货移动类型(例如122)且引用原始PO的物料凭证。 事件类型 explicit | |||
| 采购申请已批准 | 表示采购申请已正式获批,可以转换为采购订单。该事件根据采购申请数据中发布状态字段的变化推断得出,相关变化由SAP的发布策略工作流跟踪。 | ||
| 为什么重要 跟踪审批对于识别下单前阶段的瓶颈、确保符合审批政策至关重要。此处的延迟会直接影响整体采购周期时间。 获取位置 根据采购申请表EBAN的变更日志推断,重点监控发布状态字段的变化,例如EBAN-FRGZU,或分析CDHDR/CDPOS中针对EBAN对象的变更凭证。 采集 监控EBAN发布状态字段的变更凭证,以识别最终审批的时间戳。 事件类型 inferred | |||
| 采购订单已删除 | 表示采购订单项目被取消或逻辑删除,无法继续收货或开票等处理。这是一个推断事件,在PO项目上设置删除指示器时记录。 | ||
| 为什么重要 这是表示订单已取消的终止活动。分析订单被删除的原因和时间,有助于发现需求规划或供应商选择方面的问题。 获取位置 根据变更凭证CDHDR/CDPOS推断,这些记录显示采购订单项目的删除指示器EKPO-LOEKZ被设置为“L”。 采集 从变更凭证中识别EKPO-LOEKZ标志被设置时的时间戳。 事件类型 inferred | |||
| 采购订单已变更 | 表示采购订单初次创建后发生的任何修改,例如数量、价格或交付日期变更。这些变更会明确记录在SAP的变更凭证系统中。 | ||
| 为什么重要 频繁变更,尤其是审批后的变更,通常表明流程低效、初始规划不足或范围蔓延。此活动是PO返工与变更仪表板及相关KPI的基础。 获取位置 明确记录在采购订单对象EINKBELEG对应的变更凭证抬头表CDHDR和项目表CDPOS中。每次变更都会生成一条带时间戳的新记录。 采集 从与采购订单编号关联的CDHDR和CDPOS表中提取变更事件及时间戳。 事件类型 explicit | |||
| 采购订单已拒绝 | 当审批人在审批工作流中拒绝采购订单时,会发生此活动。这是一个推断事件,根据PO发布策略数据中的状态变化得出,表示订单已被拒绝。 | ||
| 为什么重要 跟踪拒绝情况有助于识别PO数据质量问题、政策不合规或审批矩阵问题。此类问题通常会导致返工并延长整体周期时间。 获取位置 根据采购订单发布状态的变更凭证CDHDR/CDPOS推断。通常在发布代码被取消或设置特定拒绝状态时记录拒绝。 采集 监控变更日志,识别发布代码取消或表示拒绝的状态变化。 事件类型 inferred | |||
提取指南
步骤
- 创建ABAP程序:使用事务代码SE38打开ABAP编辑器。为新程序输入名称,例如Z_PM_PO_EXTRACT,然后点击“创建”。输入标题,例如“Process Mining PO Data Extraction”,并将类型设置为“可执行程序”。
- 定义选择屏幕:在程序中定义选择屏幕参数,以便用户筛选要提取的数据。关键参数包括采购订单创建日期范围、公司代码(BUKRS)和采购凭证类型(BSART)。
- 定义数据结构:声明与最终事件日志格式一致的内表结构。该结构应包含所有必需和推荐的属性:PurchaseOrder、Activity、EventTime、UserName、VendorNumber、OrderAmount、MaterialGroup、CompanyCode和DocumentType。
- 实现数据选择逻辑:编写核心ABAP逻辑,为14项必需活动分别选择数据。这需要查询EKKO、EKPO、EKBE、EBAN、CDHDR、CDPOS和NAST等多个SAP表。为每项活动使用单独的子程序(PERFORM),以保持代码结构清晰。
- 选择采购申请数据:查询EBAN表,获取“Purchase Requisition Created”活动,并通过EKPO表将其关联到采购订单。使用变更日志表(CDHDR、CDPOS),通过跟踪发布状态字段的变更来识别“Purchase Requisition Approved”活动。
- 选择采购订单核心活动:查询EKKO和EKPO表,获取“Purchase Order Created”活动。针对对象EINKBELEG使用变更日志表(CDHDR、CDPOS),根据发布指示符、删除标记等特定字段的变更,提取“Purchase Order Changed”“Purchase Order Approved”“Purchase Order Rejected”“Purchase Order Completed”和“Purchase Order Deleted”活动。
- 选择采购订单通信活动:查询NAST表,查找采购订单已成功传输的记录,获取“Purchase Order Sent to Vendor”活动。
- 选择货物和服务活动:查询EKBE表中的物料凭证过账记录,根据移动类型类别识别“Goods Receipt Posted”和“Goods Returned”活动。查询ESSR和ESLL中的服务条目表,获取“Services Confirmation Entered”活动。
- 选择质量管理活动:如果使用质量管理模块,则查询QALS和QAVE表,识别与采购订单关联的检验批何时作出使用决策,该事件对应“Quality Inspection Performed”活动。
- 合并并格式化数据:将所有单独查询的结果汇总到一个最终内表中。确保EventTime字段采用统一格式,例如YYYY-MM-DDTHH:MI:SS。
- 实现文件下载:添加将最终内表下载为文件的功能。建议使用制表符分隔或CSV格式,可通过GUI_DOWNLOAD函数模块实现。
- 执行并保存:使用事务SE38或SA38执行程序。填写选择条件并运行报告。系统提示时,将输出文件以.csv扩展名保存到本地计算机,准备上传。
配置
- 日期范围:必须为提取定义明确的日期范围,通常依据采购订单创建日期(EKKO-AEDAT)。通常可先选择3至6个月,以平衡数据量和流程洞察。
- 公司代码(BUKRS):按一个或多个公司代码筛选,将提取范围限制在相关法人实体内。这是影响性能和分析相关性的关键参数。
- 采购凭证类型(BSART):按特定凭证类型筛选,例如使用“NB”表示标准采购订单,以聚焦标准流程,并在必要时排除特殊采购类型。
- 数据粒度:提取以采购订单行项目级别为设计粒度。Case ID为采购订单编号(EBELN)。包括收货在内的所有活动,即使发生在行项目级别,也会关联回此主Case ID。
- 性能注意事项:对于大型数据集,请将程序安排为后台作业(SM36),以避免超时错误。确保WHERE子句使用的关键字段已建立数据库索引,尤其是CDHDR和CDPOS等表。
- 前提条件:运行报告的用户需要具备访问ABAP工作台(SE38)的权限,以及程序开发和执行权限。同时还需要对所有底层表拥有读取权限,包括EKKO、EKPO、EKBE、CDHDR、CDPOS、EBAN、NAST、ESSR和QM表。
a 示例查询 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)在内的多个大型表,可能消耗大量资源。强烈建议在业务低峰期运行提取,或针对复制的非生产数据库执行,以避免影响系统性能。
- 变更凭证日志:Approved、Rejected、Completed和Changed等活动的准确性取决于SAP中相关字段是否启用了变更凭证日志。请与SAP管理员确认该日志已启用(通过事务SCDO)。
a 示例查询 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(检验批)。
- 提取“Purchase Order Created”:创建以EKKO表为数据源的数据流。根据所需日期范围(例如使用AEDAT)和组织范围(例如使用BUKRS筛选公司代码、使用BSART筛选凭证类型)筛选记录。将EKKO.EBELN映射到PurchaseOrder,将“Purchase Order Created”映射到Activity,并合并AEDAT和ERZET生成EventTime。映射其他必需属性。
- 提取“Goods Receipt Posted”:创建以MSEG为数据源、并通过MBLNR和MJAHR与MKPF连接的独立数据流。筛选相关移动类型,例如“101”。将MSEG.EBELN映射到PurchaseOrder,将“Goods Receipt Posted”映射到Activity,并使用MKPF.CPUDT和MKPF.CPUTM生成EventTime。
- 提取基于变更的活动(审批、变更、删除):创建以CDHDR和CDPOS为数据源、通过CHANGENR连接的数据流。该数据源可用于派生多项活动。
- 筛选OBJECTCLAS = “EINKBELEG”和TABNAME = “EKPO”。
- 对于**“Purchase Order Approved”**,筛选发布状态字段的变更,例如FNAME = “FRGZU”,其中新值(VALUE_NEW)表示最终审批通过。
- 对于**“Purchase Order Deleted”**,筛选删除指示符的变更(FNAME = “LOEKZ”),其中新值为“L”。
- 对于**“Purchase Order Changed”**,筛选其他相关字段的变更,并排除用于其他活动的特定状态字段。
- 对于所有这些活动,使用CDHDR.UDATE和CDHDR.UTIME生成EventTime。
- 提取“Purchase Requisition”活动:从EBAN创建数据流,获取“Purchase Requisition Created”活动。要将其关联到PurchaseOrder案例,请使用申请编号(BANFN)和行项目(BNFPO)将EBAN与EKPO连接。对于“Purchase Requisition Approved”,使用OBJECTCLAS = “BANF”的CDHDR/CDPOS数据。这需要仔细映射,以确保活动关联到最终生成的采购订单。
- 提取“PO Sent to Vendor”:创建以NAST表为数据源的数据流。筛选OBJECTKEY(包含采购订单编号)、相关输出类型(KSCHL)和成功处理状态(VSTAT = “1”)。使用ERDAT和UHR生成EventTime。
- 合并活动流:在ETL工具中使用“Union”或“Merge”转换,合并前述步骤创建的所有独立数据流输出。确保所有数据流的列名和数据类型一致,包括PurchaseOrder、Activity、EventTime等。
- 转换数据类型和格式:确保EventTime列转换为统一的时间戳格式,例如YYYY-MM-DD HH:MM:SS。将OrderAmount转换为标准小数格式。
- 定义目标位置:为合并后的数据流配置目标或“sink”。通常使用CSV或Parquet等扁平文件。配置分隔符、文本限定符和表头选项。
- 执行并验证:运行完整的ETL作业。检查输出文件,确认14项活动均已存在、行数合理且关键属性已正确填充。
- 安排并导出:验证完成后,安排ETL作业定期运行,例如每晚运行,以保持数据最新。生成的文件现在可以上传到您的流程挖掘工具。
配置
- 前提条件:商业ETL工具(例如Informatica PowerCenter、Talend、SAP Data Services),以及适用于ECC的SAP Certified Connector。具备S_RFC和S_TABU_DIS权限的SAP对话用户或系统用户,可访问所需数据表。
- SAP连接:连接器必须配置SAP应用服务器、系统编号、客户端、用户和密码。建议使用Secure Network Communications(SNC)。
- 日期范围筛选:必须应用日期范围筛选,以限制数据量。通常可筛选EKKO.AEDAT(采购订单创建日期),提取最近3至12个月的数据。应在数据源端应用此筛选,避免从SAP提取过量数据。
- 组织范围筛选:始终按EKKO.BUKRS(公司代码)筛选,并考虑按EKPO.WERKS(工厂)或EKKO.EKORG(采购组织)筛选,将分析范围限定到特定业务单元。
- 单据类型筛选:使用EKKO.BSART,仅纳入相关采购订单类型,排除不属于标准P2P流程的库存转储或其他内部单据。
- 性能调优:从更改单据表(CDHDR、CDPOS)提取数据可能较慢。请确保应用OBJECTCLAS、OBJECTID和UDATE筛选条件。调整SAP连接器中的“Packet Size”设置,以优化数据传输速率。对于超大型系统,可先进行一次历史数据加载,之后按计划执行增量加载。
a 示例查询 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]); 优化P2P采购订单流程:立即开始免费试用
消除瓶颈,将周期时间缩短30%或更多。
无需信用卡,几分钟即可开始