数据模板:采购到付款 - 采购订单
你的采购到付款-采购订单数据模板
- 建议收集的属性
- 需要追踪的关键活动
- SAP ECC数据提取指南
采购到付款 - 采购订单属性
| 名称 | 描述 | ||
|---|---|---|---|
Event 时间 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)凭证的唯一标识,用作跟踪采购流程的主案例。 | ||
描述 采购订单号是贯穿从创建到最终收货与完结的核心标识。每一个唯一的PO号代表一次完整的采购流程实例。 在流程挖掘中,该属性用于重建每笔采购的端到端旅程,是基础中的基础。借此可对每张订单的周期时间、流程变体与合规性进行细粒度分析,构成整个流程模型的基石。 为何重要 这是连接所有相关事件的核心标识符,使得分析每个独立采购订单的完整生命周期成为可能。 获取方式 表:EKKO,字段:EBELN 示例 450001762345000176244500017625 | |||
供应商编号 VendorNumber | 供应商的唯一标识。 | ||
描述 这是唯一标识商品或服务供应商的代码,是采购流程中至关重要的主数据。 该属性对于以供应商为中心的分析至关重要。它有助于评估供应商的交付绩效、比较不同供应商的交付周期,并分析支出模式。它是“供应商交付绩效”仪表板的主要维度。 为何重要 支持供应商绩效分析,帮助识别可靠的供应商,以及导致延迟或质量问题的供应商。 获取方式 表:EKKO,字段:LIFNR 示例 100345V-20598700112 | |||
公司代码 CompanyCode | 发起采购的法人实体或公司标识。 | ||
描述 在SAP中,公司代码代表一个独立的法律实体。所有业务凭证都以公司代码为层级入账,因此它是最基础的组织单元。 按公司代码分析流程,可横向比较不同业务单元或国家的采购效率与合规性。这样既能复用表现优秀实体的最佳实践,也能定位在流程上存在困难的具体单位。 为何重要 表示法人实体,可用于在组织不同单元间进行流程绩效对比与合规检查。 获取方式 表:EKKO,字段:BUKRS 示例 10002100US01 | |||
凭证类型 DocumentType | 用于区分不同采购订单类型的编码。 | ||
描述 凭证类型是SAP中的配置项,用于控制编号范围、字段选择以及采购订单的整体流程。例如,标准PO、服务类PO或库存调拨订单可能使用不同的凭证类型。 该属性是强有力的分析维度,因为不同凭证类型往往对应有意设计的差异化流程。按凭证类型筛选,可更准确地进行“同类对比”,衡量周期时长与流程走法的差异。 为何重要 区分不同类型的采购流程(如标准、服务、退货),这些流程通常路径不同、绩效预期也不同。 获取方式 表: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 | |||
供应商名称 VendorName | 供应商的法定名称。 | ||
描述 供应商的名称,比供应商编号更便于识别,通常来自供应商主数据。 供应商编号用于关联与唯一标识,而供应商名称更适合用于面向业务用户的仪表板与报表。对于不熟悉供应商编码的业务用户,它能让分析更直观、更易懂。 为何重要 提供易读的供应商名称,让业务用户更易理解仪表板与报告。 获取方式 表:LFA1,字段:NAME1。需将EKKO-LIFNR与LFA1-LIFNR进行关联。 示例 Staples Inc.Global Tech Solutions办公用品公司 | |||
最后数据更新 LastDataUpdate | 指示源系统数据上次刷新时间的时间戳。 | ||
描述 此属性记录最近一次数据抽取或更新的日期和时间,用于体现所分析数据的时效性。 在仪表板上展示该信息至关重要,便于用户判断洞察基于接近实时的数据还是历史快照,从而管理预期,确保基于已知数据时效的决策。 为何重要 告知用户数据的时效性,确保他们了解分析是否反映了最新的运行状态。 获取方式 此时间戳在执行时由数据提取或ETL流程生成并添加。 示例 2023-10-27T02:00:00Z2023-10-28T02:00:00Z | |||
工厂 Plant | 货物计划交付的实体地点或工厂。 | ||
描述 工厂是一个组织单元,代表生产设施、仓库或其他接收货物或服务的地点。 按工厂分析有助于理解采购流程的地域差异。它可以揭示供应商向不同地点的交付时效差异,或指出某些工厂在收货环节效率偏低,从而支持对收货及时性的分析。 为何重要 指定收货地点,可用于分析区域间的流程差异与物流绩效。 获取方式 表:EKPO,字段:WERKS 示例 100011002000 | |||
拒绝原因 RejectionReason | 用于解释采购申请或采购订单被拒绝原因的代码或文本。 | ||
描述 此属性用于记录在审批工作流中采购订单被拒绝的具体原因。该信息对理解返工和延迟的根因至关重要。 分析拒绝原因有助于找出常见问题,如价格错误、预算超支或供应商选择不合规。基于这些洞察,企业可以直击根因,提高PO首次创建质量,简化审批流程。 为何重要 直接洞察审批失败原因,便于有针对性改进,减少返工并缩短审批周期。 获取方式 该信息往往不易定位,可能存放在长文本字段中,或依赖自定义工作流配置,通常需要具体的实施知识才能获取。 示例 价格错误超出预算重复请求 | |||
是否为审批后变更 IsPostApprovalChange | 标记初次审批通过后是否发生PO变更。 | ||
描述 当同一PO中“采购订单已批准”之后又出现“采购订单已变更”时,此布尔属性为true,用于定位发生在流程后期的问题性变更。 该计算字段直接支撑“审批后PO变更率”KPI与“采购订单返工与变更”仪表板,帮助量化并突出会引发延迟且需重新审批的变更,从而暴露初始规格或范围界定阶段的问题。 为何重要 直接衡量审批后的返工情况,这是评估流程稳定性与效率的关键KPI。高返工率通常意味着上游需求定义存在问题。 获取方式 这是一个计算属性,基于事件日志中的活动序列推导而来。 示例 truefalse | |||
是否准时交付 IsOnTimeDelivery | 标记货物是否在要求的交货日期当日或之前入库。 | ||
描述 当“收货过账”的时间戳早于或等于“要求交货日期”时,此布尔属性为true,为每个PO行项目提供清晰的到货表现二元结果。 该属性是“准时收货率”KPI的基础。它便于对准时与延迟交付进行聚合与筛选,从而简化对供应商绩效及内部收货效率的分析。 为何重要 为交付及时性提供清晰的达成与未达成指标,直接支撑供应商绩效KPI与仪表板。 获取方式 这是一个计算属性,通过比较收货过账日期(EKBE-BUDAT)与要求交货日期(EKPO-EINDT)得出。 示例 truefalse | |||
期望交货日期 RequestedDeliveryDate | 企业要求供应商交付货物或服务的日期。 | ||
描述 这是采购订单中指定的目标交货日期。它作为衡量实际交付绩效的基准。 此日期对于计算“货物准时收货率”KPI至关重要。通过将实际收货日期与该请求日期进行比较,企业可以量化衡量供应商可靠性和内部收货效率,这直接支持“供应商交付绩效”仪表板。 为何重要 这是目标交货日期,对于计算准时交付KPI和评估供应商可靠性至关重要。 获取方式 表:EKPO,字段:EINDT 示例 2023-06-102023-07-222023-08-01 | |||
源系统 SourceSystem | 数据提取来源系统。 | ||
描述 此属性用于标识数据来源,通常是SAP ECC实例标识(如“ECC_PROD_100”)。在多系统环境中,可用于区分数据源。 从治理与数据血缘角度,明确源系统至关重要。这有助于确保数据完整性,并在不同ERP系统或模块合并数据时,定位数据抽取或数据质量问题。 为何重要 用于标识数据来源,这对数据治理、校验以及跨系统分析管理至关重要。 获取方式 这通常是在数据抽取过程中写入的静态值,用于标记数据集的来源系统。 示例 SAP_ECC_PRODECC_EU_100S4H_FIN | |||
端到端周期时间 EndToEndCycleTime | 一张采购订单从第一个活动到最后一个活动所经历的总用时。 | ||
描述 该指标衡量整个采购订单流程的总持续时间,从最早记录的事件(例如,“采购申请已创建”)到最终事件(例如,“采购订单已完成”)。 这是衡量整体流程效率的关键KPI。它提供了一个高层次的绩效视图,其分析有助于识别运行时间最长的案例和普遍存在的瓶颈。它直接支持“端到端采购订单周期时间分析”仪表板和“平均端到端采购订单周期时间”KPI。 为何重要 衡量整体采购流程的速度与效率,是评估流程健康度的关键指标。 获取方式 这是一个计算属性,对每个流程实例,用最后一次事件的时间戳减去第一次事件的时间戳计算得到。 示例 10天4小时22天1小时5天8小时 | |||
货币 Currency | 采购订单金额所用的货币代码。 | ||
描述 此属性指明采购订单的币种,如USD、EUR或GBP,为所有金额提供必要背景。 对全球化组织而言,币种是做好财务分析的前提。它使订单金额能够被正确汇总与比较,且所有金额类KPI都需结合其币种解读。 为何重要 为所有金额提供必要的币种背景,确保财务分析准确,尤其适用于跨国组织。 获取方式 表:EKKO,字段:WAERS 示例 美元EURJPY | |||
采购申请 PurchaseRequisition | 在采购订单之前对应的采购申请标识。 | ||
描述 此属性将采购订单关联回其来源的采购申请;并非所有PO都有前置申请。 该关联是分析“申请转订单转化”仪表板与“PR到PO转化率”KPI的关键。它可衡量从最初需求到正式下单的上游流程效率,并识别无申请创建的非合规PO。 为何重要 将采购订单与其来源采购申请关联,便于分析PR到PO的转化过程,并识别未有前置申请就创建的PO。 获取方式 表:EKPO,字段:BANFN 示例 1001589010015891 | |||
采购组 PurchasingGroup | 负责该采购活动的具体采购员或采购组。 | ||
描述 采购组代表负责某类采购活动的个人或采购团队,是供应商的主要联络窗口。 与采购组织相比,该属性提供了更细粒度的分析维度。它有助于了解采购员之间的工作量分配与绩效差异,从而为资源配置与培训提供依据。 为何重要 细化呈现采购责任归属,支持在采购员或团队层面开展工作量与绩效分析。 获取方式 表:EKKO,字段:EKGRP 示例 001002N01 | |||
采购组织 PurchasingOrganization | 负责议价并采购物料或服务的组织单元。 | ||
描述 采购组织是SAP中负责采购活动的关键组织单元,可在全公司集中设置,也可按工厂或区域分散设置。 按采购组织分析流程绩效,有助于识别哪些团队效率更高。可比较不同组织单元的周期时间、返工率与成本等指标,沉淀最佳实践并发现需要支持的领域。 为何重要 标识负责的采购团队,便于跨组织单元进行绩效对比与分析。 获取方式 表:EKKO,字段:EKORG 示例 1000US01DE01 | |||
采购到付款 - 采购订单活动
| 活动 | 描述 | ||
|---|---|---|---|
已创建采购申请 | 该活动标志着针对商品或服务的正式需求被创建。当用户保存一条新的采购申请(如事务码ME51N)时,会显式产生此事件,并在EBAN表生成唯一记录。 | ||
为何重要 这是采购流程的主要起点。分析从该事件到采购订单创建的时间,有助于衡量将内部需求转化为可执行订单的效率。 获取方式 在采购申请抬头表(EBAN)产生记录时写入。创建日期(EBAN-BADAT)与时间作为本事件的时间戳。 捕获 根据创建日期识别EBAN表中的新增记录。 事件类型 explicit | |||
收货已过账 | 该活动表示针对某一采购订单的实物收货。过账收货(如事务码MIGO)是一个显式动作,会生成物料凭证并更新库存。 | ||
为何重要 这是用于跟踪供应商交付绩效并启动发票校验流程的关键里程碑,可用于计算准时交付率与收货及时性。 获取方式 在创建物料凭证时记录。事件时间戳取自物料凭证抬头表(MKPF)的过账日期(MKPF-BUDAT)或创建日期(MKPF-CPUDT),并通过行项目表(MSEG)与PO关联。 捕获 使用MKPF表中引用采购订单的物料凭证的过账/创建时间戳。 事件类型 explicit | |||
采购订单已创建 | 该活动表示正式采购订单被创建,它与供应商构成具有约束力的合同。用户创建并保存PO(如事务码ME21N)时会显式记录此事件,并在EKKO与EKPO表产生记录。 | ||
为何重要 标志着采购订单生命周期的正式开始,是衡量PR到PO转化时长及端到端履行时长的关键里程碑。 获取方式 取自采购订单抬头表(EKKO)中的创建日期(EKKO-AEDAT),按对应的采购订单号(EKKO-EBELN)关联。 捕获 使用EKKO表中每个新采购订单的创建时间戳。 事件类型 explicit | |||
采购订单已发送给供应商 | 该活动表示已获批准的采购订单被正式发送给供应商,如通过EDI、电子邮件或打印。当输出消息成功处理时,消息控制相关表会显式记录此事件。 | ||
为何重要 这是启动供应商交付周期计时的关键里程碑。分析从该事件到收货的用时,是评估供应商绩效与交付及时性的关键。 获取方式 记录在消息状态表(NAST)中。当相关PO输出类型的处理状态(NAST-VSTAT)为'1'(处理成功)时,可从NAST-DATVR和NAST-UHRVR获取时间戳。 捕获 使用NAST表中采购订单输出消息的处理时间戳。 事件类型 explicit | |||
采购订单已完成 | 表示某个采购订单行被视为已完全交付。此为推断的事件,通常基于该行的“交货完成”指示器被自动或手动设置为有效。 | ||
为何重要 该活动作为履约环节的逻辑终点,用于计算从创建到完成的PO端到端周期时间。 获取方式 根据变更文档(CDHDR/CDPOS)推断:当PO行的“交货完成”指示器(EKPO-ELIKZ)被设为“X”时。最后一行被标记为完成通常意味着整张PO已完成。 捕获 从变更文档中提取设置EKPO-ELIKZ指示器时的时间戳。 事件类型 inferred | |||
采购订单已批准 | 表示采购订单的最终批准,授权其发送给供应商。该关键里程碑通常通过PO释放状态变为“完全释放”或“已批准”来推断。 | ||
为何重要 该活动对于计算“PO审批周期”KPI并发现审批工作流中的瓶颈至关重要;它也是后续大多数活动(如向供应商发送订单)的前提。 获取方式 通过跟踪采购订单抬头表(EKKO)的变更日志(CDHDR/CDPOS)进行推断:当最终释放码被应用,或整体释放状态指示器(EKKO-FRGKE)被设为“已释放”时。 捕获 识别PO整体释放状态(EKKO-FRGKE)变为最终批准状态时的时间戳。 事件类型 inferred | |||
已发起采购订单审批 | 表示已创建或已变更的采购订单按其配置的释放策略已提交审批。当释放策略被触发、PO进入待审批状态时,可推断出该事件。 | ||
为何重要 区分PO创建与审批流程的启动,有助于精准衡量审批周期时间这一KPI,并暴露审批开始前的等待时滞。 获取方式 根据采购订单(对象EINKBELEG)的变更文档(CDHDR/CDPOS)推断:当首次设置释放状态,或当整体释放状态(EKKO-FRGKE)首次被设为表示审批流程已激活的值时。 捕获 识别首次触发PO释放策略的那条变更文档记录。 事件类型 inferred | |||
已录入服务确认 | 对于服务类采购订单,此活动表示服务已完成的确认。该步骤通过创建服务验收单(如交易码ML81N)产生明确的事件。 | ||
为何重要 这相当于服务收货,对于跟踪服务订单的完成情况至关重要。它会触发服务付款的财务流程。 获取方式 取自服务验收单抬头表(ESSR)的创建日期(ESSR-ERDAT)。与采购订单的关联在ESLL表中。 捕获 使用ESSR表中与采购订单关联的服务录入表的创建时间戳。 事件类型 explicit | |||
已执行质量检验 | 表示已收货的物料经过了质量检验。通常在收货时生成检验批,并在质量管理模块对其做出使用判定,据此推断该活动发生。 | ||
为何重要 在质量要求高的行业,此活动用于分析检验环节的时长与结果。此处延误会在收货到可投入使用之间形成瓶颈。 获取方式 依据质量管理模块进行推断:收货时会创建检验批(QALS表),当创建使用判定(QAVE表)时即标记该活动,并包含时间戳。 捕获 在QAVE表中获取与该物料凭证关联的检验批的使用判定时间戳。 事件类型 inferred | |||
已退货 | 表示将已收货物退回给供应商,常因质量问题或发错货所致。这是一个显式事件,通过以退货专用移动类型过账物料凭证来记录。 | ||
为何重要 该活动能揭示供应商质量或订单准确性的问题,是衡量流程返工的关键指标,并且是计算“收货差异率”KPI的核心输入。 获取方式 当使用退货移动类型(如“122”,退回供应商)时,会记录在物料凭证表(MKPF/MSEG)中。过账日期(MKPF-BUDAT)作为时间戳。 捕获 识别引用原始PO且具有退货移动类型(如122)的物料凭证。 事件类型 explicit | |||
采购申请审批通过 | 表示采购申请的正式批准,授权其转换为采购订单。该事件通过采购申请数据中的释放状态字段变更来推断,并由SAP的释放策略工作流进行跟踪。 | ||
为何重要 跟踪审批对于识别审批前阶段的瓶颈并确保符合审批政策至关重要。此处的延迟直接影响整体采购周期时间。 获取方式 基于采购申请表(EBAN)的变更日志进行推断:重点监控释放状态字段(如EBAN-FRGZU)的变化,或分析EBAN对象在CDHDR/CDPOS中的变更文档。 捕获 监控EBAN释放状态字段的变更文档,以获取最终批准的时间戳。 事件类型 inferred | |||
采购订单已删除 | 表示采购订单行的取消或逻辑删除,从而阻止后续处理(如收货或开票)。这是一个推断事件,当PO行被设置删除标识时即会被捕获。 | ||
为何重要 这是表明订单已取消的终止性活动。分析订单被取消(或删除)的原因与时点,有助于发现需求计划或供应商选择中的问题。 获取方式 根据变更文档(CDHDR/CDPOS)推断:当采购订单行的删除指示器(EKPO-LOEKZ)被设为“L”时。 捕获 从变更文档中提取设置EKPO-LOEKZ指示器时的时间戳。 事件类型 inferred | |||
采购订单已变更 | 表示在采购订单初次创建后进行的任何修改,例如数量、价格或交期的调整。这些变更会被SAP的变更凭证系统明确记录。 | ||
为何重要 频繁变更,尤其是审批之后的变更,往往意味着流程低效、前期规划不足或范围蔓延。此活动是PO返工与变更仪表板及相关KPI的关键数据点。 获取方式 对于采购订单对象(EINKBELEG),所有变更都会在变更文档头表(CDHDR)与项目表(CDPOS)中显式记录,每次变更都会生成带时间戳的新条目。 捕获 从与采购订单号关联的CDHDR和CDPOS表中提取变更事件及其对应的时间戳。 事件类型 explicit | |||
采购订单被拒绝 | 在审批工作流中,审批人拒绝采购订单时发生该活动。此为推断事件,基于PO释放策略数据的状态变化判断已发生拒绝。 | ||
为何重要 跟踪拒绝有助于识别采购订单数据质量问题、政策不合规或审批矩阵内部问题。这通常会导致返工并增加整体周期时间。 获取方式 根据采购订单释放状态的变更文档(CDHDR/CDPOS)推断:当释放码被取消或设置了特定的拒绝状态时,通常记录为驳回。 捕获 监控变更日志,关注释放码被取消或状态变更为拒绝的记录。 事件类型 inferred | |||
提取指南
步骤
- 创建ABAP程序:通过事务码SE38打开ABAP编辑器,输入新程序名称(如Z_PM_PO_EXTRACT),单击“Create”。填写标题(如“Process Mining PO Data Extraction”),类型选择“Executable Program”。
- 定义选择屏幕:在程序中设置选择屏幕参数,方便用户筛选需要抽取的数据。关键参数包括采购订单创建日期范围、公司代码(BUKRS)和采购凭证类型(BSART)。
- 定义数据结构:声明与最终事件日志格式一致的内部表结构。该结构应包含所有必填和推荐的属性:PurchaseOrder、Activity、EventTime、UserName、VendorNumber、OrderAmount、MaterialGroup、CompanyCode、DocumentType。
- 实现数据选择逻辑:为14项必需活动编写核心ABAP逻辑,需要联查多个SAP表,如EKKO、EKPO、EKBE、EBAN、CDHDR、CDPOS和NAST。为保持代码清晰,建议为每个活动编写独立子例程(PERFORM)。
- 选择采购申请数据:查询EBAN表获取“采购申请已创建”事件,并通过EKPO将其关联到采购订单。利用变更日志表(CDHDR、CDPOS)跟踪释放状态字段,以识别“采购申请已批准”事件。
- 选择采购订单核心事件:查询EKKO与EKPO表获取“采购订单已创建”。在对象EINKBELEG上使用变更日志表(CDHDR、CDPOS),基于释放标识、删除标志等字段的变更,抽取“采购订单已变更”“采购订单已批准”“采购订单已拒绝”“采购订单已完成”“采购订单已删除”等事件。
- 选择PO通信事件:查询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”),将分析聚焦于标准流程,必要时排除特殊采购类型。
- 数据粒度:抽取以采购订单行项目为粒度,但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 Schema:连接数据库并确认存放SAP表的主Schema,常见为SAPSR3、SAPHANADB或类似的系统名。若该Schema不是当前用户的默认Schema,请在查询中为所有表名加上该前缀。
- 审阅SQL查询:在客户端打开提供的SQL脚本。该脚本通过关联多张SAP表,从采购到付款(P2P)流程中提取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 Schema名称。
- 执行查询:在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等表的相应权限。
- 日期范围过滤:必须应用日期范围以控制数据量。通常先按3–6个月范围筛选EKKO.AEDAT(PO变更日期)。范围过大可能导致查询执行时间极长。
- 关键数据过滤:为确保分析聚焦,请始终按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 Certified Connector。在ETL工具的管理控制台中,新建与SAP ECC的连接。需提供应用服务器主机、系统号、客户端号(Client),以及具备相应RFC和表读取权限的专用SAP账号。
- 确定源表:在ETL作业或数据流中,将所需SAP表配置为数据源。核心表包括EKKO(采购订单抬头)、EKPO(采购订单行项目)、EBAN(采购申请)、CDHDR(变更文档抬头)、CDPOS(变更文档明细)、MSEG(物料凭证明细)、MKPF(物料凭证抬头)、NAST(消息状态)、ESSR(服务验收单抬头)、QALS(检验批)。
- 抽取“采购订单已创建”:以EKKO为源创建数据流。按时间范围(如使用AEDAT)与组织范围(如公司代码BUKRS、单据类型BSART)过滤。将EKKO.EBELN映射到PurchaseOrder,将“采购订单已创建”映射到Activity,EventTime由AEDAT与ERZET组合生成,同时映射其他必要属性。
- 抽取“已过账收货”:以MSEG为源,并按MBLNR、MJAHR与MKPF关联;筛选相关移动类型,如“101”。将MSEG.EBELN映射到PurchaseOrder,将“已过账收货”映射到Activity,EventTime使用MKPF.CPUDT与MKPF.CPUTM。
- 抽取基于变更的事件(审批、变更、删除):以CDHDR与CDPOS为源,按CHANGENR关联。可由此派生多种活动。
- 过滤条件:OBJECTCLAS = 'EINKBELEG' 且 TABNAME = 'EKPO'。
- 对于**“采购订单已批准”**:筛选释放状态字段(如FNAME = 'FRGZU')且新值(VALUE_NEW)表示最终批准的记录。
- 对于**“采购订单已删除”**:筛选删除标识(FNAME = 'LOEKZ')的新值为“L”。
- 对于**“采购订单已变更”**:筛选其他相关字段变更,排除用于其他活动的特定状态字段。
- 以上事件的EventTime均使用CDHDR.UDATE与CDHDR.UTIME。
- 抽取“采购申请”事件:从EBAN获取“采购申请已创建”。为将其关联到PurchaseOrder流程实例,通过请购单号(BANFN)与行项目(BNFPO)将EBAN与EKPO关联。对于“采购申请已批准”,在CDHDR/CDPOS中使用OBJECTCLAS = 'BANF',并做好映射,确保事件关联到最终的PO。
- 抽取“PO已发送至供应商”:以NAST为源,按OBJECTKEY(包含PO号)、相关输出类型KSCHL以及处理成功状态(VSTAT = '1')过滤。EventTime使用ERDAT与UHR。
- 合并活动流:在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)及其对应的SAP ECC认证连接器;并准备一个SAP对话或系统用户,拥有针对所需表的S_RFC与S_TABU_DIS授权。
- SAP连接:在连接器中配置SAP应用服务器、系统编号、客户端、用户与密码。建议启用安全网络通信(SNC)。
- 日期范围过滤:务必使用日期范围以控制数据量。常见做法是在源端按最近3–12个月的EKKO.AEDAT(PO创建日期)筛选,避免从SAP抽取过量数据。
- 组织范围过滤:务必按EKKO.BUKRS(公司代码)过滤,并视需要按EKPO.WERKS(工厂)或EKKO.EKORG(采购组织)进一步聚焦于特定业务单元。
- 单据类型过滤:使用EKKO.BSART仅保留相关采购订单类型,排除库存调拨等不属于标准P2P流程的内部单据。
- 性能优化:从变更文档表(CDHDR、CDPOS)抽取可能较慢,务必在OBJECTCLAS、OBJECTID与UDATE上加过滤。可调整SAP连接器中的“Packet Size”以优化传输速率。对于超大系统,建议先进行历史全量加载,随后按计划执行增量加载。
a 查询示例 config
/*
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]);