您的库存管理数据模板
您的库存管理数据模板
- 建议收集的属性
- 用于流程发现的关键跟踪活动
- 专为 SAP S/4HANA 定制的提取指南
库存管理属性
| 名称 | 描述 | ||
|---|---|---|---|
| Event 时间 EventTime | 系统记录库存活动的精确日期和时间。 | ||
| 描述 Event Time 是记录活动发生确切时间的 timestamp。该数据点对于按时间顺序排列事件以重构每个库存批次的流程流转至关重要。它是所有基于时间的 Process Mining 分析的基础。 Event Time 的准确性对于计算周期时间、提前期和持续时间等关键绩效指标 (KPI) 至关重要。它能够分析不同时期的流程绩效,帮助识别瓶颈发生的时刻,并为理解流程延迟(例如批次在释放前在质检环节停留的时间)提供事实依据。 为何重要 此时间戳按时间顺序排列事件,是所有时长和绩效计算的基础。 获取方式 这通常是来自物料凭证抬头表 MKPF 的过账日期 (MKPF-BUDAT) 和录入时间 (MKPF-CPUTM) 的组合。 示例 2023-10-26T09:00:00Z2023-11-15T14:35:10Z2024-01-05T23:15:00Z | |||
| 库存批次/批号 InventoryBatchLot | 特定数量产品的唯一标识符,作为追踪其生命周期的 Case ID。 | ||
| 描述 库存批次或批号是主要的 Case ID,它将与特定、独立数量产品相关的所有活动组合在一起。这实现了对库存变动过程的完整按时间顺序的回溯:从最初入库,到各种内部移动和状态变更,直至最终用于销售、生产或处置。 在流程分析中,此属性至关重要。它允许您追踪每个批次的端到端流程,准确测量周期时间,识别流程差异,并了解不同批次的处理方式。对于制药、食品饮料和化工等对追溯、质控和保质期管理要求极高的行业,批次级别的流程分析不可或缺。 为何重要 这是将所有相关库存事件连接成单个 Case 的核心标识符,使端到端流程分析成为可能。 获取方式 这通常是批号,可在 SAP 表 MCHA(批次主记录)或 MCH1(批次)的字段 CHARG 中找到。 示例 B001-A452023L202405-XYZ789456123BATCH-05-24 | |||
| 活动 ActivityName | 库存管理流程中特定时间点发生的业务事件名称。 | ||
| 描述 “活动”属性描述了批次库存生命周期中的单个步骤或事件。这些事件代表关键业务动作,如收货、移库、质检或发货。每项活动都是对库存批次在特定时间点所发生情况的记录。 活动分析是 Process Mining 的基石。它实现了流程流向的可视化,能识别高频和低频路径,检测活动延迟的瓶颈,并分析返工循环。通过了解“库存报废”或“质检”等活动的顺序和频率,企业可以精准发现流程改进空间,提升运营效率。 为何重要 它定义了流程步骤,实现了库存生命周期的可视化与深度分析。 获取方式 这是一个派生属性,通常从 SAP 移动类型 (MSEG-BWART) 或交易代码 (MKPF-TCODE2) 映射到更易读的名称。 示例 收货过账完成上架移库已过账交货发货已过账库存已报废 | |||
| 工厂 Plant | 代表存放库存的设施(如工厂或配送中心)的组织单位。 | ||
| 描述 工厂是 SAP 中的核心组织单位,可以代表生产设施、中心仓库或公司总部。所有库存都在物理或逻辑上归属于某个工厂。 按工厂进行分析是比较不同物理位置流程性能的基础。它有助于回答诸如“哪个工厂的上架周期最长?”或“工厂 A 的库存差异率是否高于工厂 B?”等问题。这种地理或组织层面的切分,是识别特定地点问题并在整个组织内分享最佳实践的关键。 为何重要 支持对比公司不同地点的库存流程及绩效表现。 获取方式 存在于物料凭证行项目表 MSEG 的 WERKS 字段(工厂)。 示例 10001710DE01US01 | |||
| 库存地点 StorageLocation | 工厂内物料物理存放的特定位置。 | ||
| 描述 库存地点是一个组织单位,用于区分工厂内的物料库存。例如,一个工厂可能为原材料、成品和质检库存设有独立的库存地点。 此属性提供了比工厂更细致的位置信息。在分析中,它用于了解不同库存区域之间的移动情况,例如从收料区到主仓库的转储提前期。按库存地点分析存储利用率和移动频率,有助于优化仓库布局和内部物流。 为何重要 提供工厂内库位的颗粒化视图,有助于分析内部移动及仓储效率。 获取方式 存在于物料凭证行项目表 MSEG 的 LGORT 字段(库存地点)。 示例 0001RM01FG01QI01 | |||
| 异动类型 MovementType | SAP 中用于控制货物移动如何过账的三位代码。 | ||
| 描述 移动类型是 SAP 库存管理中的关键控制键,决定了物料移动的特征。它规定了更新哪些账户、交易界面的布局方式,以及哪些数量或价值字段会被更新。例如,“101”用于收货,“311”用于转移过账,“551”用于报废。 此属性通常是派生易于理解的“活动”名称的基础。按移动类型分析流程可以提供库存流动情况的详细技术视图。这对于验证流程图的准确性以及识别可能导致瓶颈或偏差的特定交易类型非常关键。 为何重要 对每个库存事件进行精确的技术分类,这对于定义活动及开展详细分析至关重要。 获取方式 存在于物料凭证行项目表 MSEG 的 BWART 字段(移动类型)。 示例 101311261551601 | |||
| 数量 Quantity | 库存移动中涉及的物料数量。 | ||
| 描述 此属性代表在给定活动中移动、接收、发出或调整的物料量。它以物料的基本计量单位进行记录。 分析数量对于理解库存流程的规模和影响至关重要。它支持创建可视化货物处理量的控制台,例如“按 SKU 分类的高级发货吞吐量”。此外,它还用于计算“库存报废/处置率”等 KPI,为流程分析提供除事件计数外的定量维度。 为何重要 量化每项活动中的物料量,支持吞吐量、报废量及调整影响的分析。 获取方式 存在于物料凭证行项目表 MSEG 的 MENGE 字段(数量)。 示例 10012.55000-10 | |||
| 物料编号 MaterialNumber | 所管理产品或物料的唯一标识符。 | ||
| 描述 物料编号通常被称为 SKU(库存单位),是分配给特定产品的唯一代码。它是库存管理中的核心主数据元素,用于跟踪货物的数量、价值和移动。 在 Process Mining 中,按物料编号进行分析可以提供以产品为中心的库存流程视图。它有助于解答诸如“哪些产品的质检时间最长”、“哪些物料报废最频繁”或“哪些物料的内部转移量最大”等问题。这种细分对于识别特定产品的问题以及针对不同类型的商品优化库存策略至关重要。 为何重要 支持按产品进行细分分析,从而发现特定物料特有的模式和问题。 获取方式 存在于物料凭证行项目表 MSEG 的 MATNR 字段。主数据位于表 MARA。 示例 RM-1001FG-2050-B100-400-A | |||
| 用户名称 UserName | 在 SAP 中执行该交易的用户的 ID。 | ||
| 描述 此属性捕获了过账凭证或执行活动的员工 SAP 用户 ID。它展示了谁对库存管理流程中的特定操作负责,从而实现可追溯性。 按用户分析对于理解绩效、合规性和培训需求至关重要。例如,“手动库存调整驱动因素”控制台利用此属性查看谁执行的调整最多,这有助于识别需要额外培训的用户,发现未经授权的操作,或表彰表现卓越的员工。 为何重要 提供追责机制,并帮助识别特定用户的操作行为、培训需求或合规性问题。 获取方式 存在于物料凭证抬头表 MKPF 的 USNAM 字段(用户名)。 示例 JSMITHMBROWNWAREHOUSE_OPS | |||
| 移动原因代码 MovementReasonCode | 指定库存移动原因的代码。 | ||
| 描述 移动原因代码为货物移动的执行背景提供了补充信息。它通常用于解释计划外移动,如库存调整、退货或报废。 该属性对于根本原因分析非常有价值。在“手动库存调整驱动因素”控制台中,按原因代码分析可以揭示差异发生的原因,如损坏、失窃或录入错误。这些见解有助于企业从源头解决底层问题,而不仅仅是治标不治本。 为何重要 深入解析计划外库存移动背后的原因,实现针对性的根本原因分析。 获取方式 存在于物料凭证行项目表 MSEG 的 GRUND 字段(移动原因)。 示例 00010005102 | |||
| Unit Of Measure UnitOfMeasure | 衡量物料数量的单位(如件、千克)。 | ||
| 描述 计量单位规定了“数量”属性的单位。常见的例子包括件 (PC)、千克 (KG)、升 (L) 或箱 (BOX),为数量字段提供了关键背景。 虽然通常作为简单的描述符使用,但该属性对于确保数据质量以及在需要将不同单位转换为统一标准的分析中非常重要。例如,为了准确计算报废库存的总价值,必须理解并可能转换不同单位下的数量。 为何重要 为“数量”属性提供必要的背景信息,确保物料体积的解读准确无误。 获取方式 存在于物料凭证行项目表 MSEG 的 MEINS 字段(基本计量单位)。 示例 PCKG个 (EA)M | |||
| 储位 StorageBin | 仓库中最细粒度的存储单元,物料物理存放在此处。 | ||
| 描述 仓位代表仓库中的特定坐标,例如货架位置。这种详细程度通常在实施了 SAP 仓库管理 (WM) 或扩展仓库管理 (EWM) 时使用。 对于“仓库存储利用率”仪表板,此属性至关重要。它允许分析仓库空间的有效利用程度,识别潜在的拥堵热点,并揭示低效的上架或拣货路径。通过分析仓位之间的移动,有助于优化仓库布局并缩短操作人员的行走时间。 为何重要 提供最细致的库位数据,支持对仓库空间利用率及运营效率的分析。 获取方式 如果使用 WM,可以在转储单表(如 LTAK/LTAP)中找到。对于库存凭证,可能在 MSEG-LGPBE 中。请咨询 SAP S/4HANA 文档。 示例 A-01-01-AB-05-10-CRCV-AREA-01 | |||
| 最后数据更新 LastDataUpdate | 指示此 record 数据上次从源系统刷新的 timestamp。 | ||
| 描述 此属性记录了从源系统进行最新数据提取或更新的日期和时间。它提供了有关所分析信息时效性的关键元数据,帮助用户明确是在查看近乎实时的信息,还是在查看过去某个时段的快照。 在任何分析中,了解数据的时效性都是得出相关且准确结论的关键。该字段允许分析人员和业务用户确认数据的最新状态,并通常显示在控制台中,为呈现的洞察提供背景参考。 为何重要 告知用户数据的更新时间,确保分析结果基于最新信息。 获取方式 此时间戳在数据提取、转换与加载(ETL)过程中生成并添加。 示例 2024-05-21T08:00:00Z2024-05-20T08:00:00Z | |||
| 到期日期 ExpirationDate | 该批次物料过期且不再可用的日期。 | ||
| 描述 货架期截止日期 (SLED) 是易腐或时效性商品的关键主数据。它在批次级别进行管理,决定了产品何时不再可售或不可消费。 此属性对于“滞销及过期库存分析”控制台必不可少。通过结合过期日期分析各项活动,企业可以识别有过期风险的批次并采取预防措施。它有助于衡量诸如“先进先出 (FEFO)”等库存周转策略的有效性,并量化因报废过期库存带来的损失。 为何重要 支持对滞销及过期库存进行分析,助力企业减少浪费并降低财务损失。 获取方式 存在于批次主表 MCH1 或 MCHA 的 VFDAT 字段(货架期到期日)。 示例 2024-12-312025-06-302024-09-01 | |||
| 库存类型 StockType | 指示库存的状态,例如无限制、质检中或已冻结。 | ||
| 描述 库存类型根据可用性对库存进行分类。主要类型包括非限制使用库存(可自由支配)、质检库存(等待质量检查)和冻结库存(不可使用)。货物流动通常涉及库存类型的变更。 追踪库存类型的变化是理解库存可用性流程的基础。它直接支持“库存过账至质检”和“库存状态变更为冻结”等活动。分析每种库存类型所花费的时间(特别是“质检”环节),是识别影响销售或生产货源可用性延迟的关键。 为何重要 追踪库存的可使用状态,这对于分析质检延迟及库存可用性至关重要。 获取方式 存在于物料凭证行项目表 MSEG 的 INSMK 字段(库存类型)。 示例 非限制使用质量检验冻结库存 | |||
| 源系统 SourceSystem | 标识数据的来源系统。 | ||
| 描述 此属性规定了库存管理数据的来源系统。在本场景中,它指特定的 SAP S/4HANA 实例。在可能从多个 ERP、仓库管理系统或遗留平台提取数据的环境中,此信息至关重要。 虽然在单系统分析中它看似是静态的,但在合并来自不同来源的数据以创建全局流程视图时,它变得必不可少。它有助于数据治理、排除数据提取问题并确保数据血缘清晰。 为何重要 提供数据来源的背景信息,这对数据治理及多系统分析不可或缺。 获取方式 这通常是在数据转换过程中设置的硬编码值,用于标识特定的 SAP S/4HANA 实例。 示例 S4H_PROD_100SAP_S4_FINANCES4HANA_GLOBAL | |||
| 物料凭证编号 MaterialDocumentNumber | 用于标识记录货物移动的物料凭证的唯一编号。 | ||
| 描述 当在 SAP 中过账货物移动时,系统会生成一份物料凭证作为移动证明。该属性是该凭证的唯一标识。一份物料凭证可包含多个项目或活动。 在流程挖掘中,“物料凭证号”是关键的交易标识符,可用于对同时过账的相关事件进行分组。它对于审计以及从流程分析下钻到源系统以调查特定交易也至关重要。 为何重要 作为审计的交易主键,支持对同时执行的活动进行分组。 获取方式 存在于表 MKPF(抬头)和 MSEG(行项目)的 MBLNR 字段(物料凭证编号)。 示例 490000123450000056784900002345 | |||
| 订单履行周期时间 OrderFulfillmentCycleTime | 从开始拣货到完成发货的端到端持续时间。 | ||
| 描述 这是一个计算指标,用于测量从“拣货开始”到“发货单过账”的总时长。它代表了流程开始后,仓库准备并发出客户订单所需的总时间。 该属性是“订单履行周期时间”KPI 的直接衡量标准。分析该时长有助于企业了解其对客户需求的响应速度。数据可以按产品、仓库或客户进行细分,以识别在拣选、包装和运输过程中何处发生了延迟,从而直接提升客户满意度和物流效率。 为何重要 衡量仓库出库流程的速度与效率,这是提升客户满意度的关键指标。 获取方式 这是一个计算属性,通过计算每个批次“拣货开始”与“发货单过账”事件之间的时间差得出。 示例 7200144003600 | |||
| 质量检验周期时间 QualityInspectionCycleTime | 批次在放行前进行质量检验的持续时间。 | ||
| 描述 此计算指标衡量了给定库存批次从“库存过账至质检”到“质检库存放行”之间的时间间隔。它代表了货物因质量控制流程而无法使用的时长。 该属性直接支持“质检周期时间”KPI 和控制台。通过计算和分析这一持续时间,企业可以识别质量流程中的瓶颈,对比不同物料或工厂的表现,并寻找简化检验流程的机会,从而提高整体库存可用性并缩短前置时间。 为何重要 量化由质量控制引起的延迟,揭示提高库存可用性和流程速度的机会。 获取方式 这是一个计算字段,通过查找质检阶段开始活动和结束活动的时间戳差值得出。 示例 2880086400172800 | |||
库存管理活动
| 活动 | 描述 | ||
|---|---|---|---|
| 上架移库已过账 | 表示批次从接收或暂存区到最终储位的物理移动。这在 SAP 中记录为转移过账物料凭证。 | ||
| 为何重要 完成入库收货流程。完成此活动所需的时间(称为上架时间)是衡量仓库效率的关键 KPI。 获取方式 在 MATDOC 表中记录为转移过账,通常发生在库位之间(例如移动类型 311)。具体移动取决于仓库结构。 捕获 通过 MATDOC 中的转储凭证进行识别,这些凭证将库存从临时/接收库存地点移动到最终存放库存地点。 事件类型 explicit | |||
| 交货发货已过账 | 记录出库流程的最后一步,即将批次的所有权转移给客户或承运人。这是一项显式交易,会减少库存并进行财务过账。 | ||
| 为何重要 这是订单履行流程中的关键完成事件。对于衡量准时交付率和计算整体订单履行周期时间至关重要。 获取方式 在 MATDOC 表中记录。由针对销售订单交货发货的移动类型 (BWART) 识别,通常为 601。 捕获 从 MATDOC 中的物料凭证中提取,移动类型为 601。 事件类型 explicit | |||
| 库存已报废 | 标记库存批次的最终处置,将其永久从库存记录中移除。这通常适用于过期、损坏或滞销的库存。 | ||
| 为何重要 这是一个代表财务损失的终止事件。分析报废事件有助于识别库存老化、装卸程序或需求预测方面的问题。 获取方式 在 MATDOC 表中记录。由报废移动类型 (BWART) 识别,例如 551(来自非限制)、553(来自质检)或 555(来自冻结)。 捕获 从 MATDOC 中的物料凭证中提取,对应报废移动类型(例如 551)。 事件类型 explicit | |||
| 库存调整已过账 | 记录由于实物库存盘点或其他差异导致的库存数量变化。此事件明确调整账面库存以匹配实物盘点数。 | ||
| 为何重要 这些调整对于维持库存准确性至关重要。调整频率过高通常预示着在库存搬运、安全或数据录入方面存在潜在问题。 获取方式 在 MATDOC 表中记录。由盘点移动类型 (BWART) 识别,例如 701(盘盈)或 702(盘亏)。 捕获 从 MATDOC 中的物料凭证中提取,对应实地盘点调整移动类型(例如 701, 702)。 事件类型 explicit | |||
| 收货过账完成 | 标记库存批次首次进入仓库,通常来自供应商或生产线。在 SAP S/4HANA 中,收货时会创建物料凭证,从而明确记录该事件。 | ||
| 为何重要 这是库存生命周期的主要起始事件。分析从该活动到其他活动(如上架)的时间,对于衡量收货区效率至关重要。 获取方式 在 MATDOC 表中记录。由特定移动类型 (BWART) 识别,例如用于采购订单收货的 101 或收货入冻结库存的 103。 捕获 从 MATDOC 中的物料凭证中提取,对应收货移动类型。 事件类型 explicit | |||
| 生产发货已过账 | 表示生产订单或流程订单对库存批次的消耗。此交易会减少库存并将物料成本分配给制造订单。 | ||
| 为何重要 这是一个主要的消耗事件,标志着组件库存生命周期的结束。对于分析生产物料可用性及消耗模式至关重要。 获取方式 在 MATDOC 表中记录。由针对订单发货的移动类型 (BWART) 识别,例如 261。 捕获 从 MATDOC 中的物料凭证中提取,移动类型为 261。 事件类型 explicit | |||
| 质检库存已放行 | 表示批次已通过质检,现在可用于生产或上架。这记录为从质检库存到另一种库存类型(如无限制使用)的显式转储。 | ||
| 为何重要 这一里程碑标志着质量流程的完成,库存变为可用状态。此环节的延迟会导致生产或履行环节出现严重的下游问题。 获取方式 在 MATDOC 表中记录为转移过账。通常由移动类型 (BWART) 321 识别,将库存从“质检”转为“非限制使用”。 捕获 从 MATDOC 中的物料凭证中提取,移动类型为 321。 事件类型 explicit | |||
| 内部库存转储已过账 | 捕获同一工厂内不同库存地点或仓位之间的库存批次移动。这是一个创建物料凭证的显式交易。 | ||
| 为何重要 追踪内部转移有助于分析仓库运营效率,识别不必要的移动,并测量不同地点间库存补货的前置时间。 获取方式 在 MATDOC 表中记录。通常由库位间转移的移动类型 (BWART) 311 识别。 捕获 从 MATDOC 中的物料凭证中提取,对应内部库存移动类型(例如 311)。 事件类型 explicit | |||
| 已开始拣货 | 标记订单履行流程的开始,即创建仓库任务以从储位拣选批次。这通常在创建转库单 (Transfer Order) 或仓库任务时捕获。 | ||
| 为何重要 此活动是拣货流程的触发点。分析从该事件到拣选完成的时间,有助于衡量仓库操作员的效率并识别延迟。 获取方式 这通常不在 MATDOC 中。在拥有仓库管理 (WM/EWM) 的系统中,这是从转库单(LTAK 表)或仓库任务的创建时间戳推断出来的。 捕获 通过与物料批次关联的转储单(WM 中)或仓库任务(EWM 中)的创建记录推断。 事件类型 inferred | |||
| 库存已过账至质检 | 表示将收到的批次移至质量检验持有状态,在通过检验前不可使用。这是 SAP 中的显式交易,会更改该批次的库存类型。 | ||
| 为何重要 此活动启动了质量检验流程。该活动与质检放行之间的时间间隔,是衡量质量相关延迟的关键指标。 获取方式 在 MATDOC 表中记录。可以是库存类型 (INSMK) 设置为“Q”(质检)的收货移动(如 101),也可以是转移过账(如 322)。 捕获 通过 MATDOC 中将库存置于“质检”库存类型的物料凭证进行识别。 事件类型 explicit | |||
| 库存状态已变更为冻结 | 表示批次状态的变化,使其无法发货(通常由于损坏、冻结请求或其他原因)。这在 SAP 中属于显式转移过账。 | ||
| 为何重要 突出显示库存供应中断的情况。高频率的冻结事件可能表明搬运、存储条件或供应商质量存在问题。 获取方式 在 MATDOC 表中记录为转移过账。通常使用移动类型 (BWART) 344 将库存从“冻结”转为“非限制”,使用 343 将库存从“非限制”转为“冻结”。本活动对应 343。 捕获 通过 MATDOC 中移动类型为 343 的物料凭证进行识别。 事件类型 explicit | |||
| 库存状态已变更为非限制使用 | 表示批次状态的变化,将其从冻结或质检暂扣中放行,使其变为可用。这被记录为显式转移过账。 | ||
| 为何重要 此活动标志着库存冻结状态的解除。分析库存处于冻结状态的时间,有助于优化问题解决流程。 获取方式 在 MATDOC 表中记录为转移过账。移动类型 (BWART) 344 将库存从“冻结”转为“非限制使用”。 捕获 通过 MATDOC 中移动类型为 344 的物料凭证进行识别。 事件类型 explicit | |||
| 批次状态已变更 | 反映批次主记录的更改,例如将其状态从“非限制”更改为“受限”。这不属于物料移动,而是对主数据的更改,该操作会被记录在日志中。 | ||
| 为何重要 批次状态的变更直接影响其在销售或生产中的可用性。分析这些变更可以揭示与库存过期或质量控制相关的问题,这些问题往往不涉及物理移动。 获取方式 通过批次主表(MCH1、MCHA)的变更日志推断。CDHDR 和 CDPOS 表跟踪批次状态字段 (MCH1-ZUSTD) 的变更。 捕获 源自 CDHDR/CDPOS 中关于批次主记录状态字段 (MCH1-ZUSTD) 的变更文档。 事件类型 inferred | |||
| 收到销售退货 | 捕获先前发出的批次从客户处返回仓库。这是一个增加库存的显式交易。 | ||
| 为何重要 追踪退货对于了解产品质量问题和客户不满至关重要。此外,处理和处置退货的流程也可能是效率低下的根源。 获取方式 在 MATDOC 表中记录。由销售退货的移动类型 (BWART) 识别,例如 651(转至非限制)或 653(转至质检)。 捕获 从 MATDOC 中的物料凭证中提取,对应销售退货移动类型(例如 651, 653)。 事件类型 explicit | |||
提取指南
步骤
- 建立系统访问权限:确保您的用户具有在 SAP S/4HANA 系统中查询核心数据服务 (CDS) 视图的必要授权。这通常需要系统管理员授予权限。
- 选择 SQL 客户端:选择一个能连接到 SAP HANA 数据库的 SQL 客户端工具。常见的选择包括 SAP HANA Studio、SAP HANA Database Explorer 或 DBeaver 等第三方工具。
- 配置数据库连接:使用 SQL 客户端创建新的数据库连接。您需要准备好 HANA 数据库主机名、端口号(通常为 3<实例编号>15)以及您的数据库用户凭据。
- 准备 SQL 查询:将本文档“query”部分提供的完整 SQL 查询语句复制到 SQL 客户端的编辑器中。
- 设置查询参数:在查询中找到占位符。您必须将
I_MaterialDocumentItem.PostingDate BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'替换为您所需的日期范围,例如BETWEEN '20230101' AND '20230630'。此外,根据您的组织结构更新任何公司或工厂特定的过滤器,如MaterialDocumentItem.Plant IN ('Plant1', 'Plant2')。 - 执行查询:在 S/4HANA 数据库上运行修改后的 SQL 查询。执行时间取决于日期范围和系统中库存数据的量。
- 检查数据:查询完成后,在 SQL 客户端中查看结果,确保 data 正确且完整。检查各项活动是否存在以及关键属性是否已填充。
- 导出事件日志:将 SQL 客户端中的完整结果集导出为 CSV 文件。确保导出设置使用 UTF-8 编码,以防止出现乱码问题。
- 准备上传:将 CSV 文件中的列名设置为与查询中的别名完全一致,例如
InventoryBatchLot、ActivityName、EventTime等。该文件现在即可上传到 Process Mining 工具。
配置
- 权限设置:运行查询的用户需要对以下 CDS views 具有
SELECT权限:I_MaterialDocumentItem、I_BatchChangeDocument和I_WarehouseTask。此外,还需要访问这些视图所在的底层数据库模式。 - 日期范围筛选:务必对
PostingDate、ChangeDocumentCreationDate或WarehouseTaskCreationDate字段应用日期范围过滤。建议分析范围为 3 到 12 个月。查询多年的 data 可能会导致严重的性能问题。 - 组织机构筛选:为了获得更好的性能并进行针对性分析,请添加
WHERE子句以按Plant或CompanyCode进行过滤。这能减少数据量,让提取过程集中在相关的业务部分。 - 数据量提示:请注意,库存管理系统会产生海量 data。过大的日期范围可能导致数百万行记录,从而影响提取时的源系统以及客户端工具的性能。
- 扩展仓库管理 (EWM):‘Picking Initiated’ 活动依赖于
I_WarehouseTaskCDS view,只有在使用 SAP Extended Warehouse Management 时该视图才会有值。如果您的组织使用的是旧版仓库管理 (WM) 模块或仅使用库存管理 (IM),则无法提取此特定活动。
a 查询示例 sql
SELECT
mat_doc.Batch AS "InventoryBatchLot",
CASE
WHEN mat_doc.MovementType = '101' AND mat_doc.InventoryStockType = '2' THEN 'Stock Posted to Quality Inspection'
WHEN mat_doc.MovementType = '101' THEN 'Goods Receipt Posted'
WHEN mat_doc.MovementType = '321' THEN 'Quality Inspection Stock Released'
WHEN mat_doc.MovementType = '311' THEN 'Internal Stock Transfer Posted'
WHEN mat_doc.MovementType = '344' THEN 'Stock Status Changed to Blocked'
WHEN mat_doc.MovementType IN ('343', '322') THEN 'Stock Status Changed to Unrestricted'
WHEN mat_doc.MovementType IN ('701', '702') THEN 'Inventory Adjustment Posted'
WHEN mat_doc.MovementType = '601' THEN 'Goods Issue for Delivery Posted'
WHEN mat_doc.MovementType = '261' THEN 'Goods Issue for Production Posted'
WHEN mat_doc.MovementType IN ('651', '653') THEN 'Sales Return Received'
WHEN mat_doc.MovementType = '551' THEN 'Stock Scrapped'
WHEN mat_doc.MovementType = '313' THEN 'Put-Away Transfer Posted' -- Example for two-step transfers
ELSE 'Unknown Material Movement'
END AS "ActivityName",
TO_TIMESTAMP(mat_doc.PostingDate || LPAD(mat_doc.CreationTime, 6, '0'), 'YYYYMMDDHH24MISS') AS "EventTime",
mat_doc.Material AS "MaterialNumber",
mat_doc.CreatedByUser AS "UserName",
mat_doc.MovementType AS "MovementType",
mat_doc.Plant AS "Plant",
mat_doc.StorageLocation AS "StorageLocation",
mat_doc.QuantityInEntryUnit AS "Quantity",
mat_doc.ReasonForMovement AS "MovementReasonCode"
FROM
I_MaterialDocumentItem AS mat_doc
WHERE
mat_doc.Batch IS NOT NULL AND mat_doc.Batch <> ''
AND mat_doc.PostingDate BETWEEN '20230101' AND '20231231' -- Placeholder: Set your date range
-- AND mat_doc.Plant IN ('Plant1', 'Plant2') -- Placeholder: Add filters for relevant plants
UNION ALL
SELECT
SPLIT_PART(change_doc.ChangeableObjectDescription, '/', 3) AS "InventoryBatchLot",
'Batch Status Changed' AS "ActivityName",
change_doc.ChangeDocumentCreationDateTime AS "EventTime",
SPLIT_PART(change_doc.ChangeableObjectDescription, '/', 1) AS "MaterialNumber",
change_doc.ChangedByUser AS "UserName",
NULL AS "MovementType",
SPLIT_PART(change_doc.ChangeableObjectDescription, '/', 2) AS "Plant",
NULL AS "StorageLocation",
NULL AS "Quantity",
NULL AS "MovementReasonCode"
FROM
I_BatchChangeDocument AS change_doc
WHERE
change_doc.ChangeDocumentTable = 'MCHA' AND change_doc.ChangeDocumentTableFieldName = 'ZUSTD'
AND TO_VARCHAR(change_doc.ChangeDocumentCreationDate) BETWEEN '20230101' AND '20231231' -- Placeholder: Set your date range
UNION ALL
SELECT
wh_task.Batch AS "InventoryBatchLot",
'Picking Initiated' AS "ActivityName",
wh_task.WarehouseTaskCreationDateTime AS "EventTime",
wh_task.Product AS "MaterialNumber",
wh_task.CreatedByUser AS "UserName",
NULL AS "MovementType",
wh_task.Plant AS "Plant",
wh_task.SourceStorageLocation AS "StorageLocation",
wh_task.TargetQuantity AS "Quantity",
NULL AS "MovementReasonCode"
FROM
I_WarehouseTask AS wh_task
WHERE
wh_task.Batch IS NOT NULL AND wh_task.Batch <> ''
AND wh_task.WarehouseProcessType IN ('P210', 'P220') -- Placeholder: Adjust process types based on your picking configuration
AND TO_VARCHAR(wh_task.WarehouseTaskCreationDate) BETWEEN '20230101' AND '20231231'; -- Placeholder: Set your date range 步骤
- 建立系统访问权限:确保您的用户具有在 SAP S/4HANA 系统中查询核心数据服务 (CDS) 视图的必要授权。这通常需要系统管理员授予权限。
- 选择 SQL 客户端:选择一个能连接到 SAP HANA 数据库的 SQL 客户端工具。常见的选择包括 SAP HANA Studio、SAP HANA Database Explorer 或 DBeaver 等第三方工具。
- 配置数据库连接:使用 SQL 客户端创建新的数据库连接。您需要准备好 HANA 数据库主机名、端口号(通常为 3<实例编号>15)以及您的数据库用户凭据。
- 准备 SQL 查询:将本文档“query”部分提供的完整 SQL 查询语句复制到 SQL 客户端的编辑器中。
- 设置查询参数:在查询中找到占位符。您必须将
I_MaterialDocumentItem.PostingDate BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'替换为您所需的日期范围,例如BETWEEN '20230101' AND '20230630'。此外,根据您的组织结构更新任何公司或工厂特定的过滤器,如MaterialDocumentItem.Plant IN ('Plant1', 'Plant2')。 - 执行查询:在 S/4HANA 数据库上运行修改后的 SQL 查询。执行时间取决于日期范围和系统中库存数据的量。
- 检查数据:查询完成后,在 SQL 客户端中查看结果,确保 data 正确且完整。检查各项活动是否存在以及关键属性是否已填充。
- 导出事件日志:将 SQL 客户端中的完整结果集导出为 CSV 文件。确保导出设置使用 UTF-8 编码,以防止出现乱码问题。
- 准备上传:将 CSV 文件中的列名设置为与查询中的别名完全一致,例如
InventoryBatchLot、ActivityName、EventTime等。该文件现在即可上传到 Process Mining 工具。
配置
- 权限设置:运行查询的用户需要对以下 CDS views 具有
SELECT权限:I_MaterialDocumentItem、I_BatchChangeDocument和I_WarehouseTask。此外,还需要访问这些视图所在的底层数据库模式。 - 日期范围筛选:务必对
PostingDate、ChangeDocumentCreationDate或WarehouseTaskCreationDate字段应用日期范围过滤。建议分析范围为 3 到 12 个月。查询多年的 data 可能会导致严重的性能问题。 - 组织机构筛选:为了获得更好的性能并进行针对性分析,请添加
WHERE子句以按Plant或CompanyCode进行过滤。这能减少数据量,让提取过程集中在相关的业务部分。 - 数据量提示:请注意,库存管理系统会产生海量 data。过大的日期范围可能导致数百万行记录,从而影响提取时的源系统以及客户端工具的性能。
- 扩展仓库管理 (EWM):‘Picking Initiated’ 活动依赖于
I_WarehouseTaskCDS view,只有在使用 SAP Extended Warehouse Management 时该视图才会有值。如果您的组织使用的是旧版仓库管理 (WM) 模块或仅使用库存管理 (IM),则无法提取此特定活动。
a 查询示例 sql
SELECT
mat_doc.Batch AS "InventoryBatchLot",
CASE
WHEN mat_doc.MovementType = '101' AND mat_doc.InventoryStockType = '2' THEN 'Stock Posted to Quality Inspection'
WHEN mat_doc.MovementType = '101' THEN 'Goods Receipt Posted'
WHEN mat_doc.MovementType = '321' THEN 'Quality Inspection Stock Released'
WHEN mat_doc.MovementType = '311' THEN 'Internal Stock Transfer Posted'
WHEN mat_doc.MovementType = '344' THEN 'Stock Status Changed to Blocked'
WHEN mat_doc.MovementType IN ('343', '322') THEN 'Stock Status Changed to Unrestricted'
WHEN mat_doc.MovementType IN ('701', '702') THEN 'Inventory Adjustment Posted'
WHEN mat_doc.MovementType = '601' THEN 'Goods Issue for Delivery Posted'
WHEN mat_doc.MovementType = '261' THEN 'Goods Issue for Production Posted'
WHEN mat_doc.MovementType IN ('651', '653') THEN 'Sales Return Received'
WHEN mat_doc.MovementType = '551' THEN 'Stock Scrapped'
WHEN mat_doc.MovementType = '313' THEN 'Put-Away Transfer Posted' -- Example for two-step transfers
ELSE 'Unknown Material Movement'
END AS "ActivityName",
TO_TIMESTAMP(mat_doc.PostingDate || LPAD(mat_doc.CreationTime, 6, '0'), 'YYYYMMDDHH24MISS') AS "EventTime",
mat_doc.Material AS "MaterialNumber",
mat_doc.CreatedByUser AS "UserName",
mat_doc.MovementType AS "MovementType",
mat_doc.Plant AS "Plant",
mat_doc.StorageLocation AS "StorageLocation",
mat_doc.QuantityInEntryUnit AS "Quantity",
mat_doc.ReasonForMovement AS "MovementReasonCode"
FROM
I_MaterialDocumentItem AS mat_doc
WHERE
mat_doc.Batch IS NOT NULL AND mat_doc.Batch <> ''
AND mat_doc.PostingDate BETWEEN '20230101' AND '20231231' -- Placeholder: Set your date range
-- AND mat_doc.Plant IN ('Plant1', 'Plant2') -- Placeholder: Add filters for relevant plants
UNION ALL
SELECT
SPLIT_PART(change_doc.ChangeableObjectDescription, '/', 3) AS "InventoryBatchLot",
'Batch Status Changed' AS "ActivityName",
change_doc.ChangeDocumentCreationDateTime AS "EventTime",
SPLIT_PART(change_doc.ChangeableObjectDescription, '/', 1) AS "MaterialNumber",
change_doc.ChangedByUser AS "UserName",
NULL AS "MovementType",
SPLIT_PART(change_doc.ChangeableObjectDescription, '/', 2) AS "Plant",
NULL AS "StorageLocation",
NULL AS "Quantity",
NULL AS "MovementReasonCode"
FROM
I_BatchChangeDocument AS change_doc
WHERE
change_doc.ChangeDocumentTable = 'MCHA' AND change_doc.ChangeDocumentTableFieldName = 'ZUSTD'
AND TO_VARCHAR(change_doc.ChangeDocumentCreationDate) BETWEEN '20230101' AND '20231231' -- Placeholder: Set your date range
UNION ALL
SELECT
wh_task.Batch AS "InventoryBatchLot",
'Picking Initiated' AS "ActivityName",
wh_task.WarehouseTaskCreationDateTime AS "EventTime",
wh_task.Product AS "MaterialNumber",
wh_task.CreatedByUser AS "UserName",
NULL AS "MovementType",
wh_task.Plant AS "Plant",
wh_task.SourceStorageLocation AS "StorageLocation",
wh_task.TargetQuantity AS "Quantity",
NULL AS "MovementReasonCode"
FROM
I_WarehouseTask AS wh_task
WHERE
wh_task.Batch IS NOT NULL AND wh_task.Batch <> ''
AND wh_task.WarehouseProcessType IN ('P210', 'P220') -- Placeholder: Adjust process types based on your picking configuration
AND TO_VARCHAR(wh_task.WarehouseTaskCreationDate) BETWEEN '20230101' AND '20231231'; -- Placeholder: Set your date range 步骤
- 访问 ABAP 编辑器:登录您的 SAP S/4HANA 系统。使用事务代码
SE38打开 ABAP 编辑器。 - 创建新程序:在“程序”字段中输入新程序的名称,例如
Z_PM_INVENTORY_EXTRACT,然后点击“创建”按钮。提供描述性标题,将“类型”设置为“可执行程序”,并保存到包中。 - 定义程序参数:在程序编辑器中定义选择屏幕,作为提取的交互界面。这允许用户指定日期范围和工厂等 data 提取参数。
- 实现提取逻辑:复制“Query”部分提供的完整 ABAP 代码,并将其粘贴到 ABAP 编辑器中。此代码旨在从多个 SAP 表中提取全部 14 个所需的库存活动数据。
- 理解核心逻辑:程序通过从源表中选择每个独立库存活动的 data(如物料移动使用
MKPF和MSEG,主数据变更使用CDHDR和CDPOS)。然后使用UNION ALL将各查询结果合并到一个代表事件日志的内部表中。 - 配置文件输出:代码的最后部分处理将内部表中的合并数据写入文件。它使用
OPEN DATASET语句在 SAP 应用服务器上创建文件。您必须指定一个 SAP 系统用户具有写入权限的有效服务器路径。 - 执行程序:保存并激活 ABAP 程序 (Ctrl+F3)。按 F8 执行。在选择屏幕上,输入所需的日期范围以及任何相关的过滤器(如工厂或公司代码)。
- 作为后台作业运行:对于大数据量,务必将程序作为后台作业执行,以避免会话超时。在执行屏幕 (F8) 中,进入菜单
Program -> Execute in Background。安排在非高峰时段运行作业。 - 获取输出文件:作业完成后,在 SAP 应用服务器上找到输出文件。使用事务代码
AL11浏览服务器目录。使用事务CG3Y将文件从应用服务器下载到本地计算机。 - 准备上传:在文本编辑器或电子表格软件中打开下载的文件。确保其格式为 CSV,包含标题行,使用逗号作为分隔符,并使用双引号作为文本限定符。在上传到 Process Mining 工具前,请核对列名是否符合要求。
配置
- 过账日期范围:这是最关键的参数。我们建议分批提取 data(例如每次 3-6 个月),以确保良好的系统性能并避免系统超时。
- 工厂筛选:强烈建议按一个或多个特定工厂 (
WERKS) 进行过滤。同时为所有工厂运行提取操作会消耗极大的系统资源。 - 公司代码筛选:如果您的组织在同一系统中运行多个公司代码,可以添加可选的公司代码 (
BUKRS) 过滤条件,以进一步缩小数据范围。 - 应用服务器文件路径:ABAP 程序需要在 SAP 应用服务器上有一个预定义的有效目录路径。请确保 SAP 系统用户 (
SY-UNAME) 具有向该目录写入文件的操作系统级权限。 - 权限要求:执行此提取的用户需要拥有事务代码
SE38(用于创建和运行程序)的权限,对表MKPF、MSEG、MCH1、CDHDR、CDPOS、LTAK和LTAP的显示访问权限,以及调度后台作业 (SM36/SM37) 的能力。
a 查询示例 abap
REPORT Z_PM_INVENTORY_EXTRACT.
" ====================================================================
" SELECTION SCREEN
" ====================================================================
SELECT-OPTIONS: s_budat FOR sy-datum OBLIGATORY.
SELECT-OPTIONS: s_werks FOR mseg-werks.
PARAMETERS: p_fpath TYPE string DEFAULT '/usr/sap/trans/tmp/inventory_log.csv' OBLIGATORY.
" ====================================================================
" DATA STRUCTURES
" ====================================================================
TYPES: BEGIN OF ty_event_log,
InventoryBatchLot TYPE charg,
ActivityName TYPE string,
EventTime TYPE string,
MaterialNumber TYPE matnr,
UserName TYPE xubname,
MovementType TYPE bwart,
Plant TYPE werks_d,
StorageLocation TYPE lgort_d,
Quantity TYPE menge_d,
MovementReasonCode TYPE grund,
END OF ty_event_log.
DATA: lt_event_log TYPE TABLE OF ty_event_log.
" ====================================================================
" DATA SELECTION
" ====================================================================
START-OF-SELECTION.
SELECT
mseg~charg AS InventoryBatchLot,
'Goods Receipt Posted' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart IN ('101', '103', '105', '501', '521', '561')
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
CASE mseg~shkzg
WHEN 'H' THEN 'Stock Posted to Quality Inspection'
WHEN 'S' THEN 'Quality Inspection Stock Released'
END AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart = '321' " For QI to Unrestricted
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Put-Away Transfer Posted' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart = '311' AND mseg~shkzg = 'H' " Assume put-away is the credit side
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Internal Stock Transfer Posted' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart IN ('301', '311', '313', '315')
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
CASE mseg~bwart
WHEN '343' THEN 'Stock Status Changed to Blocked'
WHEN '344' THEN 'Stock Status Changed to Unrestricted'
END AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart IN ('343', '344')
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Inventory Adjustment Posted' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart IN ('701', '702', '711', '712')
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Goods Issue for Delivery Posted' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart = '601'
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Goods Issue for Production Posted' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart = '261'
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Sales Return Received' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart IN ('651', '653')
UNION ALL
SELECT
mseg~charg AS InventoryBatchLot,
'Stock Scrapped' AS ActivityName,
CONCAT( mkpf~cpudt, mkpf~cputm ) AS EventTime,
mseg~matnr AS MaterialNumber,
mkpf~usnam AS UserName,
mseg~bwart AS MovementType,
mseg~werks AS Plant,
mseg~lgort AS StorageLocation,
mseg~menge AS Quantity,
mseg~grund AS MovementReasonCode
FROM mseg
JOIN mkpf ON mkpf~mblnr = mseg~mblnr AND mkpf~mjahr = mseg~mjahr
WHERE mkpf~budat IN s_budat
AND mseg~werks IN s_werks
AND mseg~charg IS NOT NULL AND mseg~charg <> ''
AND mseg~bwart = '551'
UNION ALL
SELECT
ltap~charg AS InventoryBatchLot,
'Picking Initiated' AS ActivityName,
CONCAT( ltak~bdatu, ltak~bzeit ) AS EventTime,
ltap~matnr AS MaterialNumber,
ltak~bname AS UserName,
ltak~bwart AS MovementType,
ltap~werks AS Plant,
ltap~lgort AS StorageLocation,
ltap~nista AS Quantity,
'' AS MovementReasonCode
FROM ltap
JOIN ltak ON ltak~tanum = ltap~tanum
WHERE ltak~bdatu IN s_budat
AND ltap~werks IN s_werks
AND ltap~charg IS NOT NULL AND ltap~charg <> ''
UNION ALL
SELECT
SUBSTRING( cdhdr~objectid, 5, 18 ) AS InventoryBatchLot, " Object ID for BATCH is MATNR+WERKS+CHARG
'Batch Status Changed' AS ActivityName,
CONCAT( cdhdr~udate, cdhdr~utime ) AS EventTime,
SUBSTRING( cdhdr~objectid, 1, 4 ) AS MaterialNumber,
cdhdr~username AS UserName,
'' AS MovementType,
'' AS Plant,
'' AS StorageLocation,
0 AS Quantity,
'' AS MovementReasonCode
FROM cdhdr
JOIN cdpos ON cdpos~objectclas = cdhdr~objectclas
AND cdpos~objectid = cdhdr~objectid
AND cdpos~changenr = cdhdr~changenr
WHERE cdhdr~udate IN s_budat
AND cdhdr~objectclas = 'BATCH'
AND cdpos~tabname = 'MCH1'
AND cdpos~fname = 'ZUSTD'
INTO TABLE @lt_event_log.
" ====================================================================
" WRITE OUTPUT FILE
" ====================================================================
DATA: lv_string TYPE string.
DATA: lo_conv TYPE REF TO cl_abap_conv_out_ce.
lo_conv = cl_abap_conv_out_ce=>create( encoding = 'UTF-8' ).
OPEN DATASET p_fpath FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
IF sy-subrc <> 0.
MESSAGE 'Error opening file.' TYPE 'E'.
RETURN.
ENDIF.
" Write Header
lv_string = 'InventoryBatchLot,ActivityName,EventTime,MaterialNumber,UserName,MovementType,Plant,StorageLocation,Quantity,MovementReasonCode'.
TRANSFER lv_string TO p_fpath.
" Write Data
LOOP AT lt_event_log ASSIGNING FIELD-SYMBOL(<fs_log>).
CONCATENATE
<fs_log>-InventoryBatchLot
<fs_log>-ActivityName
<fs_log>-EventTime
<fs_log>-MaterialNumber
<fs_log>-UserName
<fs_log>-MovementType
<fs_log>-Plant
<fs_log>-StorageLocation
<fs_log>-Quantity
<fs_log>-MovementReasonCode
INTO lv_string
SEPARATED BY ','.
TRANSFER lv_string TO p_fpath.
ENDLOOP.
CLOSE DATASET p_fpath.
WRITE: 'Extraction complete. File written to:', p_fpath.