应付账款支付处理数据 template
应付账款支付处理数据 template
- 供应商和付款分析的核心属性
- 付款周期的基本流程里程碑
- 针对 SAP S/4HANA 系统的专业提取逻辑
应付账款付款处理属性
| 名称 | 描述 | ||
|---|---|---|---|
| Event 时间 EventTime | 活动发生的精确 timestamp。 | ||
| 描述 事件时间(Event Time)记录了活动提交到 SAP 数据库的具体日期和时间。它为 case 内按顺序排列事件提供了必要的时间维度。此 timestamp 通常由系统日志或凭证抬头中的 CPU 日期和 CPU 时间字段组合而成。 在分析中,此属性对于计算周期时间、时长和吞吐量至关重要。它能够测量各步骤之间的时间间隔(例如从收到发票到最终审批所需的时间),这对于识别瓶颈和评估 KPI 绩效(如“平均发票审批时间”)至关重要。 为何重要 它提供 events 的时间顺序,是所有基于时间的性能计算的基础。 获取方式 SAP BKPF 表字段 CPUDT (录入日期) 和 CPUTM (录入时间),或 CDHDR 字段 UDATE 和 UTIME 示例 2023-10-12T08:30:00.000Z2023-10-12T14:15:22.000Z2023-10-15T09:00:00.000Z | |||
| 发票编号 InvoiceNumber | 正在处理的供应商发票的唯一标识符。 | ||
| 描述 发票编号(Invoice Number)是在 SAP S/4HANA 系统中跟踪应付项生命周期的主键。它特指将发票过账到总账时生成的会计凭证编号。在标准 SAP 术语中,这对应于特定公司代码和会计年度内的凭证编号 (BELNR)。 在流程分析中,此属性充当 Case ID。它将所有零散的活动——从最初的发票接收和暂存,到各种审批冻结和修改,再到最后的清帐付款——关联起来。通过此标识符对事件进行分组,分析师可以重构每项付款义务的完整端到端历史。 为何重要 它作为唯一的 Case ID,能够实现付款流程流的端到端重建。 获取方式 SAP BKPF 表(会计凭证抬头)字段 BELNR 或 ACDOCA 字段 BELNR 示例 1900000523510000289119000006015100003002 | |||
| 活动 Activity | 为发票记录的特定任务或事件状态变更。 | ||
| 描述 此属性代表发票生命周期中发生的各个独立流程步骤。它捕获诸如发票创建、过账、冻结、审批和付款清帐等事件。活动名称源自源系统中的事务代码、更改日志条目或 workflow 状态更新。 在分析中,此字段对于绘制流程流转变体至关重要。它使 Process Mining 引擎能够可视化步骤顺序,识别返工循环,并确定流程在何处偏离了标准路径。它是事件日志的核心组成部分。 为何重要 它定义了流程图中的节点,从而实现了工作流 (Workflow) 和瓶颈 (Bottlenecks) 的可视化。 获取方式 源自事务代码 (TCODE) 或变更文档头 (CDHDR) 和项目 (CDPOS) 示例 发票已过账已应用付款锁定付款运行已执行发票已清算 | |||
| 最后数据更新 LastDataUpdate | 指示记录上次提取或刷新的 timestamp。 | ||
| 描述 “最后 Data 更新”标记了 data 成功加载到 Process Mining 平台的时间点。它反映的不是业务 event 的时间,而是数据集本身的新鲜度。这对于维持对分析 Dashboards 的信任至关重要。 在分析中,此属性帮助用户了解他们正在查看的信息的时效性。在监控类似付款冻结分析这类近乎实时的 Dashboards 时,这一点尤为重要,可确保基于 SAP S/4HANA 系统的最新状态做出决策。 为何重要 它通知用户 data 的新鲜度,这对于运营 Dashboards 至关重要。 获取方式 由 ETL / 提取流程生成 示例 2023-10-27T23:59:59.000Z2023-11-01T06:00:00.000Z | |||
| 源系统 SourceSystem | 数据来源的 SAP S/4HANA 实例标识符。 | ||
| 描述 此属性标识了提取流程数据的具体 ERP 安装实例或客户端。在存在多个 SAP 实例或并行运行旧系统的环境中,此字段可确保数据血缘得到维护,并支持跨系统比较。 在分析中,此字段充当高级过滤器。它帮助分析师在对不同地区系统安装的绩效进行标杆管理,或在系统迁移项目中验证数据一致性时隔离数据。它确保了由于系统配置引起的任何流程变动都能在正确的语境下得到理解。 为何重要 它区分了多系统环境中的 data 源,确保准确的细分。 获取方式 SAP 安装环境中的系统 ID (SY-SYSID) 示例 SAP_PROD_01S4H_NA_100ERP_EU_200 | |||
| 付款冻结原因 PaymentBlockReason | 指示发票付款冻结原因的代码。 | ||
| 描述 此属性包含应用于发票的特定原因代码,用于防止自动付款运行提取该发票。例如,"A" 代表付款冻结,"R" 代表发票核对,或由用户设置的手动冻结。 在分析中,此字段是 "Manual Payment Block Analysis" 仪表板的主要驱动因素。通过汇总不同冻结原因的频率,组织可以诊断出导致付款流程停滞的系统性问题,例如频繁的价格差异或收货缺失。 为何重要 它识别流程停滞的具体原因,从而实现有针对性的根本原因分析。 获取方式 SAP BSEG 表字段 ZLSPR 示例 ABR* | |||
| 付款条款 PaymentTerms | 代表约定的付款和折扣条件的键值。 | ||
| 描述 付款条件(Payment Terms)定义了发票的到期日以及是否享受早期付款的现金折扣。该代码(如 "Z001")对应 "Net 30" 或 "2% 10, Net 30" 等规则。它通常从供应商主数据复制到发票中,但也可以手动更改。 在分析中,此属性是 "Early Payment Discount Optimizer" 和 "Vendor Payment Term Compliance" 仪表板的核心。它使系统能够计算基准到期日,并识别付款是否在获取折扣的最佳窗口期内完成。 为何重要 它规定了预期的的时间线和财务激励,是折扣分析的关键。 获取方式 SAP BSEG 表字段 ZTERM 示例 Z001NT300001 | |||
| 供应商编号 VendorNumber | 与发票关联的供应商唯一标识符。 | ||
| 描述 供应商编号(Vendor Number)对应于 SAP 明细账中的特定债权人账户。它将发票关联到包含付款条件、银行详情和联系信息的主数据。在 S/4HANA 中,这通常与“业务伙伴”概念挂钩,但在许多表中仍保留了旧有的字段名 LIFNR。 在分析中,此属性是 "Vendor Payment Term Compliance" 仪表板的基础。它允许分析师按供应商汇总流程绩效,识别那些经常导致冻结、价格差异或延迟的特定供应商。它为战略采购决策和供应商关系管理提供支持。 为何重要 它能够按供应商进行性能聚合,这对于识别延迟的根本原因至关重要。 获取方式 SAP BKPF 表字段 LIFNR 或 ACDOCA 字段 LIFNR 示例 100050VEND-US-99200400 | |||
| 公司代码 CompanyCode | 为其创建资产负债表和损益表的组织单位。 | ||
| 描述 公司代码(Company Code)代表企业内独立的会计实体。它是外部会计的核心组织单位,用于构建财务数据。每张发票都精确分配到一个公司代码。 在分析中,此属性允许按法律实体或地区对 KPI 进行细分。它用于仪表板中,以比较不同子公司应付账款团队的效率。例如,它可以帮助识别特定分支机构的手动付款冻结率是否高于公司标准。 为何重要 它按法律实体对流程进行细分,从而促进内部基准测试。 获取方式 SAP BKPF 表字段 BUKRS 示例 US01DE1010002000 | |||
| 净付款到期日 NetDueDate | 为避免罚金而计算出的发票最后付款日期。 | ||
| 描述 净到期日(Net Due Date)是付款的最后截止日期。它是通过在基准日期基础上增加最大付款期限天数计算得出的。虽然有时会显式存储,但在分析视图中通常是一个计算字段。 在分析中,这是 "Late Payment and Penalty Tracker" 的主要基准。将实际清帐日期与净到期日进行比较,可得出“逾期付款天数”指标,这有助于量化应付账款 (AP) 团队的效率以及供应商摩擦的风险。 为何重要 它是流程的目标截止日期;错过它会影响信用评级并产生成本。 获取方式 计算得出:基准日期 + 最大付款条件天数 (ZBD1T/ZBD2T/ZBD3T) 示例 2023-11-302023-12-01 | |||
| 凭证类型 DocumentType | 对会计凭证进行分类(例如供应商发票、付款、贷记通知单)。 | ||
| 描述 凭证类型(Document Type)是 SAP 中用于分类会计交易的两位代码。常见类型包括供应商发票的 "KR"、供应商付款的 "KZ" 和发票收据总额的 "RE"。它决定了凭证的号码范围和字段状态。 在分析中,此属性用于过滤流程范围。例如,分析师可能希望排除贷记通知单,以专注于对外付款的效率。它还有助于识别正在处理的交易类型组合,并支持 "Process Variant Complexity" 仪表板。 为何重要 它对 case 进行分类(发票 vs. 贷记通知单),从而允许进行过滤分析。 获取方式 SAP BKPF 表字段 BLART 示例 KRREKZKG | |||
| 发票金额 InvoiceAmount | 凭证货币中的发票总额。 | ||
| 描述 此属性反映了源凭证中记录的发票财务价值。它代表必须与供应商结算的债务。在 SAP S/4HANA 中,这通常存储在“凭证货币金额”字段中。 在分析中,发票金额用于确定工作的优先级。像 "Manual Touch Point Distribution" 这样的仪表板利用此字段来突显高强度的人工活动是否被浪费在低额发票上。它使组织能够将优化重点放在流程失误会带来更大财务风险的高额交易上。 为何重要 它提供了 case 的财务权重,对于优先处理高价值的流程效率低下问题至关重要。 获取方式 SAP BKPF 或 BSEG 表字段 WRBTR 示例 1500.00250.5010000.00 | |||
| 是否无感 IsTouchless | 一个布尔标志,指示发票是否在没有人工干预的情况下处理。 | ||
| 描述 此属性通过分析 case 的事件流计算得出。如果一个 case 仅包含自动化活动(例如 "system" 用户、特定的后台事务代码),且没有手动更改或冻结,则被标记为 "touchless"(无人工干预)。 在分析中,这是 "Touchless Invoice Rate" KPI 的核心指标。它使组织能够跟踪自动化计划的成效,并识别哪些 case 类型(如按供应商或地区划分)能够成功在无需人工干预的情况下流转过系统。 为何重要 它是流程自动化和效率的主要衡量指标。 获取方式 根据 activities 序列和用户类型计算 示例 truefalse | |||
| 是否逾期支付 IsLatePayment | 一个布尔标志,指示付款是否在净到期日之后进行。 | ||
| 描述 此计算属性会在清帐日期严格晚于净到期日时评估为 "True"。它作为流程绩效的二元分类指标。 在分析中,此标记用于统计 "Late Payment Penalty Frequency" KPI 中的非合规 case 数量。它简化了仪表板的创建,通过简单的 "True" 值计数即可完成,而无需在可视化层进行复杂的日期运算。 为何重要 它简化了准时性能 KPI 的计算。 获取方式 计算得出:清账日期 > 净到期日 示例 truefalse | |||
| 用户名称 UserName | 执行特定活动的用户 ID。 | ||
| 描述 用户名(User Name)记录了负责执行流程步骤的人员或系统代理的登录 ID。这可以是手动输入数据的用户,也可以是执行自动化任务的后台作业 ID(如 "BATCH_USER")。 在分析中,此属性支持计算“活动自动化率”。通过区分人工用户和系统账户,分析师可以衡量流程的自动化水平。它还用于 "Manual Touch Point Distribution" 仪表板,以评估跨团队的工作量分布。 为何重要 它区分了手动工作和自动化工作,从而能够计算自动化率。 获取方式 SAP BKPF 表字段 USNAM 或 CDHDR 字段 USERNAME 示例 BSMITHWF-BATCHRJONES | |||
| 结清日期 ClearingDate | 发票通过付款完成清帐的日期。 | ||
| 描述 清帐日期(Clearing Date)记录了应付账款分类账中的未结项何时被冲销,通常是通过付款运行或手动付款过账完成。这标志着债务的终结。 在分析中,此属性用于计算流程的最终周期时间。它是 "Payment Cleared" 活动所使用的 timestamp,通过与净到期日对比来确定准时付款绩效。该数据直接对接 "Payment Clearing Efficiency" 仪表板。 为何重要 它标志着付款流程的完成,并用于确定付款的及时性。 获取方式 SAP BSEG 或 AUGDT 表字段 AUGDT 示例 2023-11-012023-11-15 | |||
| 会计年度 FiscalYear | 发票所属的会计年度。 | ||
| 描述 会计年度(Fiscal Year)是用于财务报告的时间段。它与公司代码和凭证编号共同构成了 SAP 财务凭证的复合主键。 在分析中,这是唯一标识 case 的技术需求,同时也支持同比报告。它确保了“发票编号”作为 Case ID 在长达数十年的数据历史中保持唯一。 为何重要 SAP FI 中用于唯一 case 识别的技术要求。 获取方式 SAP BKPF 表字段 GJAHR 示例 20232024 | |||
| 基准日期 BaselineDate | 付款条件生效及到期日计算的起始日期。 | ||
| 描述 基准日期(Baseline Date)是计算净到期日和现金折扣期的起点。根据配置和供应商主数据,它通常是发票日期或过账日期。 在分析中,此日期是计算 "Is Late" 状态的技术前提。基准日期的错误常导致过早付款(影响现金流)或逾期付款(导致罚金)。验证此日期的准确性是 "Vendor Payment Term Compliance" 分析的一部分。 为何重要 它是所有到期日计算的锚点。 获取方式 SAP BSEG 表字段 ZFBDT 示例 2023-10-012023-10-15 | |||
| 损失折扣金额 DiscountLostAmount | 原本可用但未获取的现金折扣金额。 | ||
| 描述 此计算属性代表“错失的节省机会”。它通过检查付款是否在折扣截止日期后进行来得出;如果是,则计算应用于发票金额的错失折扣价值。 在分析中,这是 "Early Payment Discount Optimizer" 的关键财务指标。它以硬通货形式量化了低效成本,为流程改进提供了极具说服力的商业理由。 为何重要 它量化了由于流程延迟造成的直接财务损失。 获取方式 计算得出:如果清账日期 > 折扣日期,则为发票金额 * 折扣 % 示例 30.000.00150.00 | |||
| 现金折扣天数 1 CashDiscountDays1 | 自基准日期起,可享受首个现金折扣的天数。 | ||
| 描述 此属性定义了最优惠付款条件的窗口期(例如 "2% 10, Net 30" 中的 "10")。它来源于发票行项目中存储的条款。 在分析中,这有助于为 "Early Payment Discount Optimizer" 确定“目标日期”。如果发票在此窗口期内结清,即可实现折扣。此字段有助于衡量处理周期过慢所产生的机会成本。 为何重要 它定义了财务节约的机会窗口。 获取方式 SAP BSEG 表字段 ZBD1T 示例 10140 | |||
| 现金折扣百分比 1 CashDiscountPercentage1 | 在首个折扣期内付款可享受的折扣百分比。 | ||
| 描述 此属性代表供应商为早期付款提供的财务激励比率(例如 "2% 10" 中的 "2")。 在分析中,这用于计算“潜在现金折扣”价值。通过将此百分比乘以发票金额,仪表板可以直观展示由于流程低效而损失的总金额,从而为自动化改进提供有力的业务依据。 为何重要 它量化了潜在的节省率,对于 ROI 计算至关重要。 获取方式 SAP BSEG 表字段 ZBD1P 示例 2.03.00.0 | |||
| 货币 Currency | 与发票金额关联的货币代码。 | ||
| 描述 币种(Currency)属性指定了发票金额的单位,如美元、欧元或英镑。它能确保财务价值被正确解读,是在跨国公司代码间汇总数据的基础。 在分析中,此字段确保财务 KPI 计算正确。它常用于将数值转换为全球仪表板的报告币种。如果没有此属性,总支出或平均发票金额等汇总指标在多币种环境下将毫无意义。 为何重要 它为财务金额提供上下文,对于准确的全球报告至关重要。 获取方式 SAP BKPF 表字段 WAERS 示例 美元EURGBPJPY | |||
| 采购单据 PurchasingDocument | 与发票关联的采购订单编号。 | ||
| 描述 此属性将发票与上游采购流程关联。它包含与发票匹配的采购订单 (PO) 编号。并非所有发票(如杂项费用)都会有 PO 参考。 在分析中,此字段对于“三单匹配率分析”至关重要。它允许分析师将有 PO 支持的发票与无 PO 发票区分开来,因为这两者的审批 workflow 通常差异巨大。它还通过将应付账款数据与采购数据关联,促进了端到端的 Process Mining。 为何重要 它将应付账款与采购联系起来,从而实现 3-way match 分析和流程扩展。 获取方式 SAP BSEG 表字段 EBELN 示例 45000012344500009876 | |||
应付账款付款处理活动
| 活动 | 描述 | ||
|---|---|---|---|
| 付款冻结已解除 | 指示先前应用的付款冻结已被解除,有效地释放了发票以进行付款。当 BSEG 中的 ZLSPR 字段从有值变为 null 或空时,即可识别出这一点。 | ||
| 为何重要 在没有明确工作流日志的系统中,通常充当“发票已批准”的代理,标记瓶颈 (Bottleneck) 期的结束。 获取方式 CDPOS 和 CDHDR 表,查找 BSEG-ZLSPR 变为空的情况。 捕获 当 CDPOS 记录 ZLSPR 移除时记录 事件类型 explicit | |||
| 付款已清算 | 标记最终对账,即供应商账户中的未结项与付款已清。从 BSEG 表中的 AUGDT(清账日期)字段捕获。 | ||
| 为何重要 流程的最终状态,表示生命周期已结束且账目平衡。手动清帐率过高表明对账效率低下。 获取方式 BSEG 表,字段 AUGDT(清账日期)。 捕获 当 AUGDT 字段有值时记录 事件类型 explicit | |||
| 付款运行已执行 | 代表付款运行的执行,即生成资金转账指令的阶段。通过 REGUH 或 REGUP 表中的状态更新进行跟踪。 | ||
| 为何重要 付款的业务承诺,对于分析付款批处理效率至关重要。 获取方式 REGUH 表,通常与运行日期和标识相关联。 捕获 当付款运行状态更新时记录 事件类型 explicit | |||
| 发票已过账 | 代表在总账中正式记录债务。此活动源自 BKPF 表中的创建时间戳或 ACDOCA 表中的分录日期。 | ||
| 为何重要 这是财务时间线的主要起点,为到期日和账龄分析奠定基准。 获取方式 BKPF 表,使用 CPUDT(输入日期)和 CPUTM(输入时间)。 捕获 当 BKPF 记录创建时记录 事件类型 explicit | |||
| 已创建付款凭证 | 生成贷记银行并借记供应商的会计凭证。这可以在 BKPF 中通过付款凭证类型(如 ZP、KZ)找到。 | ||
| 为何重要 付款的财务实现,用于计算应付账款周转天数 (DPO)。 获取方式 BKPF 表,按特定于付款的凭证类型 (BLART) 过滤。 捕获 当 BKPF 付款凭证创建时记录 事件类型 explicit | |||
| 已应用付款锁定 | 表示发票行项目已被设置付款冻结,防止其被付款运行提取。这通过变更单监控 BSEG 表中 ZLSPR 字段的变化来捕获。 | ||
| 为何重要 冻结是导致逾期付款和流程摩擦的主要原因,直接影响手动付款冻结分析 Dashboard。 获取方式 CDPOS 和 CDHDR 表(变更文档),查找字段 BSEG-ZLSPR 的更新。 捕获 当 CDPOS 记录 ZLSPR 更改时记录 事件类型 explicit | |||
| 付款建议已创建 | 表示发票已包含在付款建议运行(F110)中,这是自动付款程序的首步。从存储结算数据的 REGUH 表中捕获。 | ||
| 为何重要 指示发票已被选中进行付款,并已通过付款程序内的验证检查。 获取方式 REGUH 表创建时间戳(LAUFD 和 LAUFI 键)。 捕获 当 REGUH 记录创建时记录 事件类型 explicit | |||
| 付款条件已变更 | 记录未清发票上付款条件的更新,这会改变到期日或折扣资格。该项通过 BSEG 表中 ZTERM 字段的更改日志进行跟踪。 | ||
| 为何重要 频繁的更改暗示了主数据错误或手动覆盖,这会影响现金流预测和供应商付款条件合规性。 获取方式 CDPOS 和 CDHDR 表,查找字段 BSEG-ZTERM 的更新。 捕获 当 CDPOS 记录 ZTERM 更改时记录 事件类型 explicit | |||
| 发票到期 | 一个计算出的 timestamp,代表发票达到其净到期日的时刻。这是通过将付款条件天数添加到 BSEG 表中找到的基准日期得出的。 | ||
| 为何重要 作为准时付款性能和逾期付款罚款跟踪器的参考点。 获取方式 计算得出:BSEG-ZFBDT(基准日期)+ BSEG-ZBD1T/ZBD2T/ZBD3T(天数)。 捕获 通过比较当前日期与净到期日得出 事件类型 calculated | |||
| 发票已冲销 | 指示发票凭证已冲销或取消。通过检查 BKPF 表中的 STBLG(冲销凭证)字段捕获。 | ||
| 为何重要 代表返工和流程失效,识别浪费和潜在的重复劳动。 获取方式 BKPF 表,字段 STBLG 不为空。 捕获 当 STBLG 字段有值时记录 事件类型 explicit | |||
| 发票已暂存 | 指示发票已输入 SAP 但尚未过账到总账,通常用于初步 data 录入。这可以从 VBKPF 表中明确捕获,或者通过在 BKPF 中识别在转换为已过账之前带有暂存状态代码的凭证来捕获。 | ||
| 为何重要 暂存(Parking)标志着数据输入阶段的开始,有助于衡量收到发票到确认财务债务之间的延迟时间。 获取方式 用于暂存凭证抬头数据的 VBKPF 表,或具有特定凭证状态 (BSTAT = V) 的 BKPF 表。 捕获 当 VBKPF 分录创建时记录 事件类型 explicit | |||
| 检测到价格差异 | 推断出的 activity,指示发票价格与采购订单价格不匹配。这是通过观察在过账时自动应用的特定付款冻结键(通常是代表发票校验的 'R')得出的。 | ||
| 为何重要 识别手动返工的根本原因,并支持 3-way match 率分析。 获取方式 在过账时根据 BSEG-ZLSPR 值 'R'(或系统特定的价格冻结配置)推断。 捕获 将 ZLSPR 值与 'R' 进行比较 事件类型 inferred | |||
| 检测到数量差异 | 推断出的 activity,指示发票数量与收货数量之间存在差异。这是通过观察应用于行项目的特定付款冻结键(通常是代表数量差异的 'M')得出的。 | ||
| 为何重要 对于分析匹配效率和供应链 data 质量至关重要。 获取方式 根据 BSEG-ZLSPR 值 'M'(或系统特定的数量冻结配置)推断。 捕获 将 ZLSPR 值与 'M' 进行比较 事件类型 inferred | |||
| 现金折扣损失 | 一个计算出的 event,标记现金折扣资格过期的日期。通过将折扣到期日与当前日期或付款日期进行比较得出。 | ||
| 为何重要 对于提前付款折扣优化器可视化损失的财务机会至关重要。 获取方式 计算得出:BSEG-ZFBDT + BSEG-ZBD1T(折扣天数 1)。 捕获 通过比较日期与折扣到期日得出 事件类型 calculated | |||
提取指南
步骤
确定所需的 CDS 视图:确认标准 SAP S/4HANA CDS 视图的可用性。所需的主要视图包括 I_JournalEntry(表头)、I_OperationalAcctgDocItem(行项目/相当于 BSEG)、I_SupplierInvoice(物流)、I_PaymentProposalItem (F110) 以及 I_ChangeDocument(用于日志)。
配置用户权限:确保数据库用户或技术服务用户对 CDS 实体关联的 DDL SQL 视图拥有 SELECT 权限。这通常通过 SAP HANA Studio 或 ABAP Eclipse Development Tools (ADT) 进行管理。
准备 SQL 环境:打开 SQL 界面(例如 SAP HANA Studio、连接到 HANA 的 DBeaver 或支持 SQL 的 Process Mining 连接器)。此方法假定您可以直接以视图形式访问 HANA 层的 CDS 视图。
界定范围:确定公司代码 (CompanyCode) 和会计年度范围,以限制 data 量。在查询 Operational Accounting Document Item 视图时,这对于确保性能至关重要。
实施活动逻辑:复制下方提供的 SQL 查询。该查询使用 UNION ALL 将 14 个不同的逻辑块合并为一个单一的 event log 结构。每个块针对一个特定活动(例如:发票已过账、付款已清账)。
处理更改文档:该查询包含付款条件更改和冻结操作的部分。这些部分依赖于 I_ChangeDocument 视图。如果您使用的 S/4 版本中未激活此视图,则可能需要将基础表 (CDHDR/CDPOS) 封装在自定义 CDS 视图中。
处理计算出的 event:检查“发票到期”和“现金折扣损失”的逻辑。这些是通过在操作行项目视图中的基准日期上增加天数而生成的计算 event。
执行提取:运行查询。对于大型 data 集,强烈建议按会计年度或公司代码进行分区提取,以避免内存溢出。
验证日期格式:确保 EventTime 列的格式为 YYYY-MM-DD HH:MM:SS。SAP HANA SQL 返回的 timestamp 可能需要根据您的目标应用程序进行类型转换。
导出 data:将结果集保存为 CSV 或 Parquet 文件。确保表头与最终 SELECT 语句中定义的列相匹配。
为上传进行转换:如果您的 Process Mining 工具需要特定的 CSV 格式(例如特定的日期掩码),请在后期处理脚本中或在 SQL 中使用 TO_VARCHAR 函数进行转换。
最终验证:将样本加载到 ProcessMind 并验证 Case ID(发票编号)是否正确地将从过账到清账的所有活动归组。
配置
- 公司代码过滤器:将查询限制在特定的组织单位(CompanyCode = '1000'),以保证业务上下文的相关性和系统性能。
- 日期范围:在 PostingDate 或 CreationDate 上应用过滤器(例如过去 12 个月),以管理 data 卷。
- 账户类型:对 I_OperationalAcctgDocItem 进行过滤,设置 FinancialAccountType = 'K'(供应商),以排除总账和客户明细行。
- CDS View 激活:确保 I_JournalEntry、I_OperationalAcctgDocItem 和 I_PaymentProposalItem 视图已激活并发布,以便进行 SQL 访问。
- 变更日志性能:查询 I_ChangeDocument 可能非常耗费资源。请通过 ObjectClass 'BELEG' 以及 ZLSPR 和 ZTERM 等特定字段名来限制这些子查询。
a 查询示例 sql
/* SAP S/4HANA CDS View Extraction for Accounts Payable */
/* Combined Event Log Query */
/* 1. Invoice Parked */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Parked' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
JE.CreatedByUser AS UserName,
NULL AS ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
CASE WHEN JE.CreationDateTime > ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) THEN 'True' ELSE 'False' END AS IsLatePayment,
'False' AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K' -- Vendor
AND JE.AccountingDocumentCategory = 'V' -- Parked Document
UNION ALL
/* 2. Invoice Posted */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Posted' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
JEItem.PaymentBlockingReason AS PaymentBlockReason,
JE.CreatedByUser AS UserName,
NULL AS ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
'False' AS IsLatePayment,
CASE WHEN JE.CreatedByUser = 'BATCH_USER' THEN 'True' ELSE 'False' END AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JE.AccountingDocumentCategory <> 'V' -- Exclude Parked
UNION ALL
/* 3. Price Variance Detected (Inferred at Posting) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Price Variance Detected' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
JEItem.PaymentBlockingReason AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.PaymentBlockingReason = 'R' -- Standard SAP Price Variance Block Key
UNION ALL
/* 4. Quantity Variance Detected (Inferred at Posting) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Quantity Variance Detected' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
JEItem.PaymentBlockingReason AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.PaymentBlockingReason = 'M' -- Standard SAP Quantity Variance Block Key
UNION ALL
/* 5. Payment Block Applied (via Change Document) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Block Applied' AS Activity,
CD.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
CD.NewValue AS PaymentBlockReason,
CD.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_ChangeDocument AS CD
JOIN I_JournalEntry AS JE ON CD.ObjectValue = CONCAT(JE.CompanyCode, JE.AccountingDocument)
JOIN I_OperationalAcctgDocItem AS JEItem ON JE.AccountingDocument = JEItem.AccountingDocument AND JE.CompanyCode = JEItem.CompanyCode
WHERE CD.ObjectClass = 'BELEG'
AND CD.TableName = 'BSEG'
AND CD.FieldName = 'ZLSPR'
AND CD.OldValue IS NULL AND CD.NewValue IS NOT NULL
UNION ALL
/* 6. Payment Block Removed (via Change Document) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Block Removed' AS Activity,
CD.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
CD.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_ChangeDocument AS CD
JOIN I_JournalEntry AS JE ON CD.ObjectValue = CONCAT(JE.CompanyCode, JE.AccountingDocument)
JOIN I_OperationalAcctgDocItem AS JEItem ON JE.AccountingDocument = JEItem.AccountingDocument AND JE.CompanyCode = JEItem.CompanyCode
WHERE CD.ObjectClass = 'BELEG'
AND CD.TableName = 'BSEG'
AND CD.FieldName = 'ZLSPR'
AND CD.OldValue IS NOT NULL AND (CD.NewValue IS NULL OR CD.NewValue = '')
UNION ALL
/* 7. Payment Terms Changed (via Change Document) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Terms Changed' AS Activity,
CD.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
CD.NewValue AS PaymentTerms,
NULL AS PaymentBlockReason,
CD.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_ChangeDocument AS CD
JOIN I_JournalEntry AS JE ON CD.ObjectValue = CONCAT(JE.CompanyCode, JE.AccountingDocument)
JOIN I_OperationalAcctgDocItem AS JEItem ON JE.AccountingDocument = JEItem.AccountingDocument AND JE.CompanyCode = JEItem.CompanyCode
WHERE CD.ObjectClass = 'BELEG'
AND CD.TableName = 'BSEG'
AND CD.FieldName = 'ZTERM'
UNION ALL
/* 8. Invoice Due (Calculated) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Due' AS Activity,
TO_TIMESTAMP(ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays))) AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) < CURRENT_DATE
UNION ALL
/* 9. Cash Discount Lost (Calculated) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Cash Discount Lost' AS Activity,
TO_TIMESTAMP(ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.CashDiscount1Days))) AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.CashDiscount1Days > 0
AND (JEItem.ClearingDate IS NULL OR JEItem.ClearingDate > ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.CashDiscount1Days)))
UNION ALL
/* 10. Payment Proposal Created */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Proposal Created' AS Activity,
PPI.ProposalRunDate AS EventTime, -- Often just a date, cast to timestamp if needed
JE.CompanyCode,
PPI.Supplier AS VendorNumber,
PPI.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
PPI.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_PaymentProposalItem AS PPI
JOIN I_JournalEntry AS JE
ON PPI.CompanyCode = JE.CompanyCode
AND PPI.AccountingDocument = JE.AccountingDocument
AND PPI.FiscalYear = JE.FiscalYear
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JEItem.FinancialAccountType = 'K'
UNION ALL
/* 11. Payment Run Executed */
/* Derived from existence in payment tables with a run ID */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Run Executed' AS Activity,
PPI.PaymentRunDate AS EventTime,
JE.CompanyCode,
PPI.Supplier AS VendorNumber,
PPI.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
PPI.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_PaymentProposalItem AS PPI
JOIN I_JournalEntry AS JE
ON PPI.CompanyCode = JE.CompanyCode
AND PPI.AccountingDocument = JE.AccountingDocument
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
WHERE PPI.PaymentRunID IS NOT NULL
UNION ALL
/* 12. Payment Document Created */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Document Created' AS Activity,
PayJE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
PayJE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
PayJE.CreatedByUser AS UserName,
PayJE.PostingDate AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
JOIN I_JournalEntry AS PayJE
ON JEItem.ClearingJournalEntry = PayJE.AccountingDocument
AND JEItem.ClearingJournalEntryFiscalYear = PayJE.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.ClearingJournalEntry IS NOT NULL
UNION ALL
/* 13. Payment Cleared */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Cleared' AS Activity,
TO_TIMESTAMP(JEItem.ClearingDate) AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
'System' AS UserName,
JEItem.ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
CASE WHEN JEItem.ClearingDate > ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) THEN 'True' ELSE 'False' END AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.ClearingDate IS NOT NULL
UNION ALL
/* 14. Invoice Reversed */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Reversed' AS Activity,
RevJE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
RevJE.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
JOIN I_JournalEntry AS RevJE
ON JE.ReverseDocument = RevJE.AccountingDocument
AND JE.ReverseDocumentFiscalYear = RevJE.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JE.ReverseDocument IS NOT NULL 步骤
确定所需的 CDS 视图:确认标准 SAP S/4HANA CDS 视图的可用性。所需的主要视图包括 I_JournalEntry(表头)、I_OperationalAcctgDocItem(行项目/相当于 BSEG)、I_SupplierInvoice(物流)、I_PaymentProposalItem (F110) 以及 I_ChangeDocument(用于日志)。
配置用户权限:确保数据库用户或技术服务用户对 CDS 实体关联的 DDL SQL 视图拥有 SELECT 权限。这通常通过 SAP HANA Studio 或 ABAP Eclipse Development Tools (ADT) 进行管理。
准备 SQL 环境:打开 SQL 界面(例如 SAP HANA Studio、连接到 HANA 的 DBeaver 或支持 SQL 的 Process Mining 连接器)。此方法假定您可以直接以视图形式访问 HANA 层的 CDS 视图。
界定范围:确定公司代码 (CompanyCode) 和会计年度范围,以限制 data 量。在查询 Operational Accounting Document Item 视图时,这对于确保性能至关重要。
实施活动逻辑:复制下方提供的 SQL 查询。该查询使用 UNION ALL 将 14 个不同的逻辑块合并为一个单一的 event log 结构。每个块针对一个特定活动(例如:发票已过账、付款已清账)。
处理更改文档:该查询包含付款条件更改和冻结操作的部分。这些部分依赖于 I_ChangeDocument 视图。如果您使用的 S/4 版本中未激活此视图,则可能需要将基础表 (CDHDR/CDPOS) 封装在自定义 CDS 视图中。
处理计算出的 event:检查“发票到期”和“现金折扣损失”的逻辑。这些是通过在操作行项目视图中的基准日期上增加天数而生成的计算 event。
执行提取:运行查询。对于大型 data 集,强烈建议按会计年度或公司代码进行分区提取,以避免内存溢出。
验证日期格式:确保 EventTime 列的格式为 YYYY-MM-DD HH:MM:SS。SAP HANA SQL 返回的 timestamp 可能需要根据您的目标应用程序进行类型转换。
导出 data:将结果集保存为 CSV 或 Parquet 文件。确保表头与最终 SELECT 语句中定义的列相匹配。
为上传进行转换:如果您的 Process Mining 工具需要特定的 CSV 格式(例如特定的日期掩码),请在后期处理脚本中或在 SQL 中使用 TO_VARCHAR 函数进行转换。
最终验证:将样本加载到 ProcessMind 并验证 Case ID(发票编号)是否正确地将从过账到清账的所有活动归组。
配置
- 公司代码过滤器:将查询限制在特定的组织单位(CompanyCode = '1000'),以保证业务上下文的相关性和系统性能。
- 日期范围:在 PostingDate 或 CreationDate 上应用过滤器(例如过去 12 个月),以管理 data 卷。
- 账户类型:对 I_OperationalAcctgDocItem 进行过滤,设置 FinancialAccountType = 'K'(供应商),以排除总账和客户明细行。
- CDS View 激活:确保 I_JournalEntry、I_OperationalAcctgDocItem 和 I_PaymentProposalItem 视图已激活并发布,以便进行 SQL 访问。
- 变更日志性能:查询 I_ChangeDocument 可能非常耗费资源。请通过 ObjectClass 'BELEG' 以及 ZLSPR 和 ZTERM 等特定字段名来限制这些子查询。
a 查询示例 sql
/* SAP S/4HANA CDS View Extraction for Accounts Payable */
/* Combined Event Log Query */
/* 1. Invoice Parked */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Parked' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
JE.CreatedByUser AS UserName,
NULL AS ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
CASE WHEN JE.CreationDateTime > ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) THEN 'True' ELSE 'False' END AS IsLatePayment,
'False' AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K' -- Vendor
AND JE.AccountingDocumentCategory = 'V' -- Parked Document
UNION ALL
/* 2. Invoice Posted */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Posted' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
JEItem.PaymentBlockingReason AS PaymentBlockReason,
JE.CreatedByUser AS UserName,
NULL AS ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
'False' AS IsLatePayment,
CASE WHEN JE.CreatedByUser = 'BATCH_USER' THEN 'True' ELSE 'False' END AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JE.AccountingDocumentCategory <> 'V' -- Exclude Parked
UNION ALL
/* 3. Price Variance Detected (Inferred at Posting) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Price Variance Detected' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
JEItem.PaymentBlockingReason AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.PaymentBlockingReason = 'R' -- Standard SAP Price Variance Block Key
UNION ALL
/* 4. Quantity Variance Detected (Inferred at Posting) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Quantity Variance Detected' AS Activity,
JE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
JEItem.PaymentBlockingReason AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.PaymentBlockingReason = 'M' -- Standard SAP Quantity Variance Block Key
UNION ALL
/* 5. Payment Block Applied (via Change Document) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Block Applied' AS Activity,
CD.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
CD.NewValue AS PaymentBlockReason,
CD.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_ChangeDocument AS CD
JOIN I_JournalEntry AS JE ON CD.ObjectValue = CONCAT(JE.CompanyCode, JE.AccountingDocument)
JOIN I_OperationalAcctgDocItem AS JEItem ON JE.AccountingDocument = JEItem.AccountingDocument AND JE.CompanyCode = JEItem.CompanyCode
WHERE CD.ObjectClass = 'BELEG'
AND CD.TableName = 'BSEG'
AND CD.FieldName = 'ZLSPR'
AND CD.OldValue IS NULL AND CD.NewValue IS NOT NULL
UNION ALL
/* 6. Payment Block Removed (via Change Document) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Block Removed' AS Activity,
CD.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
CD.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_ChangeDocument AS CD
JOIN I_JournalEntry AS JE ON CD.ObjectValue = CONCAT(JE.CompanyCode, JE.AccountingDocument)
JOIN I_OperationalAcctgDocItem AS JEItem ON JE.AccountingDocument = JEItem.AccountingDocument AND JE.CompanyCode = JEItem.CompanyCode
WHERE CD.ObjectClass = 'BELEG'
AND CD.TableName = 'BSEG'
AND CD.FieldName = 'ZLSPR'
AND CD.OldValue IS NOT NULL AND (CD.NewValue IS NULL OR CD.NewValue = '')
UNION ALL
/* 7. Payment Terms Changed (via Change Document) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Terms Changed' AS Activity,
CD.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
CD.NewValue AS PaymentTerms,
NULL AS PaymentBlockReason,
CD.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_ChangeDocument AS CD
JOIN I_JournalEntry AS JE ON CD.ObjectValue = CONCAT(JE.CompanyCode, JE.AccountingDocument)
JOIN I_OperationalAcctgDocItem AS JEItem ON JE.AccountingDocument = JEItem.AccountingDocument AND JE.CompanyCode = JEItem.CompanyCode
WHERE CD.ObjectClass = 'BELEG'
AND CD.TableName = 'BSEG'
AND CD.FieldName = 'ZTERM'
UNION ALL
/* 8. Invoice Due (Calculated) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Due' AS Activity,
TO_TIMESTAMP(ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays))) AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) < CURRENT_DATE
UNION ALL
/* 9. Cash Discount Lost (Calculated) */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Cash Discount Lost' AS Activity,
TO_TIMESTAMP(ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.CashDiscount1Days))) AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
'System' AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.CashDiscount1Days > 0
AND (JEItem.ClearingDate IS NULL OR JEItem.ClearingDate > ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.CashDiscount1Days)))
UNION ALL
/* 10. Payment Proposal Created */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Proposal Created' AS Activity,
PPI.ProposalRunDate AS EventTime, -- Often just a date, cast to timestamp if needed
JE.CompanyCode,
PPI.Supplier AS VendorNumber,
PPI.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
PPI.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_PaymentProposalItem AS PPI
JOIN I_JournalEntry AS JE
ON PPI.CompanyCode = JE.CompanyCode
AND PPI.AccountingDocument = JE.AccountingDocument
AND PPI.FiscalYear = JE.FiscalYear
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JEItem.FinancialAccountType = 'K'
UNION ALL
/* 11. Payment Run Executed */
/* Derived from existence in payment tables with a run ID */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Run Executed' AS Activity,
PPI.PaymentRunDate AS EventTime,
JE.CompanyCode,
PPI.Supplier AS VendorNumber,
PPI.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
PPI.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_PaymentProposalItem AS PPI
JOIN I_JournalEntry AS JE
ON PPI.CompanyCode = JE.CompanyCode
AND PPI.AccountingDocument = JE.AccountingDocument
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
WHERE PPI.PaymentRunID IS NOT NULL
UNION ALL
/* 12. Payment Document Created */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Document Created' AS Activity,
PayJE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
PayJE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
PayJE.CreatedByUser AS UserName,
PayJE.PostingDate AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
JOIN I_JournalEntry AS PayJE
ON JEItem.ClearingJournalEntry = PayJE.AccountingDocument
AND JEItem.ClearingJournalEntryFiscalYear = PayJE.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.ClearingJournalEntry IS NOT NULL
UNION ALL
/* 13. Payment Cleared */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Payment Cleared' AS Activity,
TO_TIMESTAMP(JEItem.ClearingDate) AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
'System' AS UserName,
JEItem.ClearingDate,
ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) AS NetDueDate,
CASE WHEN JEItem.ClearingDate > ADD_DAYS(JEItem.DocumentItemDate, TO_INTEGER(JEItem.NetPaymentDays)) THEN 'True' ELSE 'False' END AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JEItem.ClearingDate IS NOT NULL
UNION ALL
/* 14. Invoice Reversed */
SELECT
JE.OriginalReferenceDocument AS InvoiceNumber,
'Invoice Reversed' AS Activity,
RevJE.CreationDateTime AS EventTime,
JE.CompanyCode,
JEItem.Supplier AS VendorNumber,
JEItem.AmountInTransactionCurrency AS InvoiceAmount,
JE.AccountingDocumentType AS DocumentType,
JEItem.PaymentTerms,
NULL AS PaymentBlockReason,
RevJE.CreatedByUser AS UserName,
NULL AS ClearingDate,
NULL AS NetDueDate,
NULL AS IsLatePayment,
NULL AS IsTouchless,
'S4HANA' AS SourceSystem,
CURRENT_TIMESTAMP AS LastDataUpdate
FROM I_JournalEntry AS JE
JOIN I_OperationalAcctgDocItem AS JEItem
ON JE.CompanyCode = JEItem.CompanyCode
AND JE.AccountingDocument = JEItem.AccountingDocument
AND JE.FiscalYear = JEItem.FiscalYear
JOIN I_JournalEntry AS RevJE
ON JE.ReverseDocument = RevJE.AccountingDocument
AND JE.ReverseDocumentFiscalYear = RevJE.FiscalYear
WHERE JEItem.FinancialAccountType = 'K'
AND JE.ReverseDocument IS NOT NULL