您的退货与退款处理数据模板
您的退货与退款处理数据模板
- 推荐收集的数据字段
- 需要跟踪的关键流程步骤
- 数据提取指南
退货与退款处理属性
| 名称 | 描述 | ||
|---|---|---|---|
| Event 时间 EventTime | 指示特定活动或事件发生时间的时间戳。 | ||
| 描述 事件时间(即时间戳)记录了某项活动发生的精确日期和时间。事件日志中的每项活动都有对应的时间戳,用以提供事件的先后顺序。 此属性对于所有基于时间的流程挖掘分析都至关重要。它用于计算活动间的周期时间、识别等待时间和瓶颈、衡量案例总时长,并检查是否符合服务水平协议(SLA)。时间戳的准确性直接影响到绩效分析的可信度。 为何重要 此 timestamp 对于计算所有基于时长的指标(如周期时间和等待时间)至关重要,是绩效分析的基础。 获取方式 对应于各种表中的创建或修改日期字段,例如订单创建的“SalesTable.createdDateTime”或仓库日记账的“WMSJournalTrans.createdDateTime”。 示例 2023-10-26T10:00:00Z2023-10-26T14:30:15Z2023-10-27T09:05:42Z | |||
| 退货 Case ID ReturnCaseId | 客户退货与退款 Case 的唯一标识符,关联所有相关 Activity。 | ||
| 描述 退货 Case ID 是每个独立退货流程实例的主标识符。它关联了从退货单创建到最终结案的所有 Activity。 在流程分析中,该 ID 是重建每笔退货端到端旅程的基础。通过该标识符,您可以跟踪完整生命周期,衡量总周期时间,并分析不同 Case 之间的变体。所有 Event、Data 和指标都通过此 ID 进行汇总和关联。 为何重要 这是连接所有流程步骤的核心 Case 标识符,使从头到尾追踪和分析每笔退货成为可能。 获取方式 这通常是“销售与市场营销”模块中的退货授权 (RMA) 编号或类型为“退货单”的销售订单号。可在 'SalesTable' 等表中找到。 示例 RMA-001234RMA-001235RMA-001236 | |||
| 活动名称 ActivityName | 退货与退款流程中发生的特定业务 Event 或任务的名称。 | ||
| 描述 此属性描述了退货与退款生命周期中的特定步骤或 Event。分析这些 Activity 的顺序和频率是 Process Mining 的核心。它支持流程图的可视化,识别步骤间的瓶颈,并发现常见或罕见的流程变体。 为何重要 它定义了流程的各个步骤,从而实现了流程流的可视化,并能识别瓶颈、返工和偏差。 获取方式 这是一个从系统 Event 中推导出的概念性属性。它可以通过将表(如 'SalesTable' 和 'WMSJournalTable')中的状态变更或特定 Event Log 映射为易于理解的名称来生成。 示例 退货单已创建项目已接收已应用处置代码贷项通知单已过账 | |||
| 产品 ID ProductId | 被退回产品的唯一标识符。 | ||
| 描述 Product ID(通常为 SKU)用于识别客户退回的具体商品。每一行退货单都与一个 Product ID 关联。 按产品分析退货对于识别高退货率商品至关重要。这可能预示着质量控制问题、产品描述不准或制造缺陷,有助于优先处理相关的调查和改进。 为何重要 支持基于每个产品的退货分析,有助于识别存在质量问题或退货量高的单品。 获取方式 这对应于退货单 'SalesLine' 表中的 'ItemId' 字段。 示例 SKU-A-123SKU-B-456SKU-C-789 | |||
| 安置代码 DispositionCode | 指示物品检验结果及建议采取的后续操作的代码。 | ||
| 描述 处置代码 (Disposition Code) 在退货商品质检期间分配。它决定了后续流程,如“退款”、“换货”、“报废”或“退还客户”。 该属性是退货流程中的关键决策点。按处置代码分析,企业可以了解退货结果,跟踪报废商品的财务影响,并评估不同解决路径(如换货与退款)的效率。 为何重要 此代码决定了退货 Case 在检验后的路径,对于分析流程变体及其业务结果至关重要。 获取方式 这是质量管理模块中的一个关键字段,与质量订单或检验订单处理相关联。 示例 CRDTREPL-D报废 (SCRAP)退回供应商 (RTV) | |||
| 负责人 ResponsibleUser | 执行或负责特定 Activity 的用户或员工。 | ||
| 描述 此属性识别负责执行流程步骤的个人用户。按用户分析流程有助于了解工作量分布、识别绩效卓越者并发现培训需求,同时确保合理的职责分离。 为何重要 它支持对工作量分配、个人或团队绩效进行分析,并能识别培训或资源分配的机会。 获取方式 可在事务记录的“创建者”或“修改者”字段中找到,例如“SalesTable.createdBy”或日记账表中的关联用户 ID。 示例 Alice.WBob.JChris.P | |||
| 退货原因代码 ReturnReasonCode | 客户提供的退货原因。 | ||
| 描述 退货原因代码记录了客户陈述的退货理由。分析退货原因是进行根因分析的关键。它有助于企业识别产品质量、描述或物流错误。基于 Data 的洞察可以推动产品设计、营销和供应链的改进,从而减少未来的退货。 为何重要 提供关于退货原因的关键洞察,支持根本原因分析,从而降低退货率并提升客户满意度。 获取方式 这通常存储在退货单行级别。请查看退货单 'SalesLine' 表中的原因代码字段。 示例 缺陷错发商品 (WRONG_ITEM)不再需要运输途中受损 | |||
| 退货渠道 ReturnChannel | 客户发起退货的方法或渠道。 | ||
| 描述 此属性指定了客户发起退货的渠道。按渠道细分流程分析有助于评估各渠道的绩效和效率,比较周期时间、成本和满意度,从而确定最佳实践和改进方向。 为何重要 它支持不同退货渠道间的绩效比较,有助于优化最高效且最具成本效益的渠道。 获取方式 此信息可能存储在退货单抬头 ('SalesTable') 中,或根据创建订单的用户推断得出。可能需要自定义逻辑或专门的字段。 示例 网络门户门店终端客户支持 | |||
| SLA 状态 SlaStatus | 指示该案例是否在服务水平协议(SLA)目标范围内解决。 | ||
| 描述 此计算属性提供了 SLA 合规状态(通常为“准时”或“逾期”)。它简化了 Dashboard 上的绩效报告,使用户无需手动对比日期即可直观了解状态,便于快速计算整体 SLA 达成率。 为何重要 提供一个简单直观的 SLA 合规指标,方便过滤出延迟案例并分析延迟的根本原因。 获取方式 这是一个派生属性,通过对比最终解决 Activity 的 timestamp 与 'RefundSlaTargetDate' 属性计算得出。 示例 准时逾期 | |||
| 仓库 ID WarehouseId | 接收退货商品的仓库或地点的标识符。 | ||
| 描述 此属性识别处理退货商品的具体仓库或退货中心。按仓库分析流程支持不同地点间的绩效对标,帮助识别最高效的设施和区域瓶颈。 为何重要 支持不同仓库或退货中心之间的绩效比较,有助于识别区域瓶颈或最佳实践。 获取方式 此信息存储在库存相关交易的 'InventLocationId' 字段中,例如到达日记账 ('WMSJournalTable') 或 'SalesLine'。 示例 WH-EASTWH-WESTCENTRAL-DC | |||
| 最后数据更新 LastDataUpdate | 指示流程数据最后一次刷新的时间戳。 | ||
| 描述 此属性记录了 Data 最后一次从源系统提取并更新到 Process Mining 工具的时间。了解最后更新时间对于确保分析的时效性、正确解读 Dashboard 和 KPI 具有重要意义。 为何重要 指示数据的实时性,确保分析人员了解流程洞察的时效性。 获取方式 这是在 Data 导入管道中生成并存储的元数据属性,通常代表 ETL 任务完成的 timestamp。 示例 2023-11-01T02:00:00Z2023-11-02T02:00:00Z | |||
| 实际退款金额 ActualRefundAmount | 发放给客户的最终退款金额。 | ||
| 描述 此属性是退还给客户的最终确认金额。这是财务分析的关键属性,直接用于“退款金额差异分析”Dashboard。分析此 Data 有助于了解退货的财务影响及处理过程中的任何调整。 为何重要 这代表了退货的实际财务影响,对于计算退款准确性和理解财务结果至关重要。 获取方式 此值可在已过账的贷记单交易详情中找到,与贷记单的 'CustTrans' 和 'CustInvoiceJour' 表相关。 示例 99.99135.000.00 | |||
| 客户ID CustomerId | 发起退货的客户的唯一标识符。 | ||
| 描述 Customer ID 是与退货关联的客户账户唯一标识符。它将退货交易关联回 CRM 或数据库中的特定客户。 按客户分析退货可以识别退货活动异常频繁的客户,这可能暗示欺诈行为或长期不满意。它还可用于客户细分,例如为高价值客户提供优先退货服务。 为何重要 它将退货流程关联到特定客户,从而支持客户层面的分析,并识别退货模式或潜在的欺诈行为。 获取方式 这是退货单 'SalesTable' 中的 'CustAccount' 字段。 示例 CUST-00045CUST-00192CUST-00315 | |||
| 是否符合政策 IsPolicyAdherent | 指示退货批准是否符合既定退货政策的标记。 | ||
| 描述 这是一个计算得出的布尔属性,指示退货是否符合公司政策。该属性直接支持“退款审批合规概览”Dashboard。它允许企业量化合规性,识别作为例外批准的 Case,并分析这些例外的频率,这对于治理和成本控制至关重要。 为何重要 它直接衡量对业务规则的遵守情况,有助于识别并减少可能导致收入损失的违规退货批准。 获取方式 这是一个派生属性。其逻辑需要通过对比退货属性(如退货日期与购买日期、退货原因)与预设业务规则来构建。 示例 truefalse | |||
| 源系统 SourceSystem | 提取 Event Data 的信息系统。 | ||
| 描述 此属性识别 Data 来源的信息系统。在大型组织中,流程可能跨越多个系统。指定每个 Event 的源系统对于 Data 治理、排查提取问题以及了解流程的技术架构至关重要。 为何重要 它提供了关于数据来源的关键背景信息,这对于数据治理、验证以及理解流程的系统全景至关重要。 获取方式 这通常是在数据提取、转换和加载 (ETL) 过程中添加的静态值,用于标记数据集的来源。 示例 Microsoft Dynamics 365 F&OD365-PROD | |||
| 申请退款金额 RequestedRefundAmount | 客户申请的退款总额。 | ||
| 描述 此属性代表退货流程开始时申请或预期的初始退款金额。通过对比申请金额与实际退款金额,企业可以识别由重置费或损毁扣款引起的差异,从而监控财务准确性和政策执行情况。 为何重要 它作为衡量财务准确性的基准,通过与实际处理的退款金额进行对比来实现。 获取方式 这通常是退回的原始销售订单行的行金额或总计金额,可在 'SalesLine.LineAmount' 中找到。 示例 99.99150.0024.50 | |||
| 结束时间 EndTime | 指示特定活动完成的时间戳。 | ||
| 描述 End Time 代表 Activity 的完成 timestamp。通过对比 StartTime 和 EndTime,分析师可以精确测量特定任务(如“商品检验”)的主动处理时间,并将其与任务间的等待时间区分开来。这有助于精准定位特定 Activity 内部而非仅仅是环节之间的效率低下问题。 为何重要 它能够计算单个活动的活动处理时间,有助于区分等待时间和实际工作时间。 获取方式 这通常需要派生。例如,它可以是结束某个 Activity 的状态变更的 'modifiedDateTime',也可以是后续 Activity 的 StartTime。 示例 2023-10-26T10:15:00Z2023-10-26T14:45:20Z2023-10-27T09:55:12Z | |||
| 贷方票据 ID CreditNoteId | 为退款创建的贷记单文件的唯一标识符。 | ||
| 描述 处理退款时会生成贷记单。此属性存储该文件的唯一 ID。 该 ID 建立了从业务流程到会计系统财务记录的直接联系,有助于审计和深入调查财务差异,使分析师能够一路追踪退货 Case 到结算它的具体财务交易。 为何重要 它将业务退货流程与相应的财务交易关联起来,这对于审计和财务对账至关重要。 获取方式 贷记单号通常位于 'CustInvoiceJour' 表的 'InvoiceId' 字段中,交易类型为“贷记单”。它可以链接回退货单。 示例 CN-10056CN-10057CN-10058 | |||
| 退款 SLA 目标日期 RefundSlaTargetDate | 退货与退款 Case 应完全解决的目标日期。 | ||
| 描述 此属性定义了解决退货 Case 的 SLA 截止日期。该目标日期对于监控服务承诺履行情况至关重要,用于计算“解决 SLA 达成率”KPI 并驱动相关 Dashboard。通过对比此日期与实际完成日期,企业可以识别 SLA 违规并主动管理逾期 Case。 为何重要 它是衡量流程绩效的基准,支持对 SLA 合规性的跟踪以及对延迟案例的识别。 获取方式 这可能不是标准字段。通常根据退货创建日期加上预设的 SLA 期限计算得出,可能存储在自定义字段中。 示例 2023-11-10T23:59:59Z2023-11-15T23:59:59Z | |||
| 退货单状态 ReturnOrderStatus | Event 发生时退货单的整体状态。 | ||
| 描述 此属性指示退货单抬头的当前状态,提供了 Case 生命周期的宏观视图。虽然 Activity 提供了细粒度的步骤,但整体状态对于筛选和细分 Case 非常有用。 为何重要 提供案例状态的高层级摘要,有助于过滤案例并理解诸如取消等结果。 获取方式 此信息位于 'SalesTable' 的 'SalesStatus' 或 'DocumentStatus' 字段中。 示例 开放订单已交付已开票已取消 | |||
| 退货类型 ReturnType | 根据预期结果(如退款或更换)对退货进行分类。 | ||
| 描述 此属性根据客户寻求或企业提供的解决方式对退货 Case 进行分类(如:退款、换货或维修)。 这种分类有助于分析不同的流程路径。退款流程与换货发货流程截然不同。按退货类型进行细分,可以更准确地分析各路径特有的周期时间和瓶颈。 为何重要 由于退款和更换流程具有不同的步骤和周期,它支持基于预期结果的细分分析。 获取方式 这可能是退货单抬头上的自定义字段,也可能是根据处置代码或后续交易(如换货订单的创建)派生出来的。 示例 退款更换店内余额 (Store Credit) | |||
退货与退款处理 Activities
| 活动 | 描述 | ||
|---|---|---|---|
| 已应用处置代码 | 此 Activity 代表检验完成以及对退回商品处理方式的决策。退货行会被分配一个处置代码(如“退款”、“报废”或“换货”)。 | ||
| 为何重要 这是一个关键的决策点,决定了随后的流程路径(退款、换货或拒绝)。此处的延迟会显著影响整体解决时间。 获取方式 当退货单行的库存交易或相关日记账中的 DispositionCode 字段被填充时,会捕获此 Event。 捕获 为退货单行设置 DispositionCode 时的更新 Event。 事件类型 explicit | |||
| 贷项通知单已过账 | 贷记单正式过账到财务总账,使退款可供客户使用。这标志着从公司角度完成了退款操作。 | ||
| 为何重要 这是一个关键的财务里程碑,确认退款已在系统中处理。它通常是衡量退款 SLA 合规性的核心 Activity。 获取方式 退货单发票日记账的过账 timestamp,标志着贷记单最终确定。退货单状态变更为“已开票”。 捕获 退货单发票日记账的过账。 事件类型 explicit | |||
| 退货单已关闭 | 退货单已达到最终状态,意味着所有实物和财务交易均已完成。这通常发生在贷记单过账或换货发出之后。 | ||
| 为何重要 这是成功完成退货流程的主要结束 Event。从创建到此时点的时长代表了 Case 的总周期时间。 获取方式 根据 ReturnOrder 状态字段更改为其最终值(如“已开票”或“已关闭”)推断。这表示预期不再有后续处理。 捕获 SalesTable.Status 或 SalesTable.DocumentStatus 字段更改为最终状态。 事件类型 inferred | |||
| 退货单已创建 | 此 Activity 标志着退货流程的开始。这是在 Dynamics 365 中创建新 ReturnOrder 记录时捕获的显式 Event。 | ||
| 为何重要 这是整个退货流程的主要开始 Event。分析从此 Activity 到其他环节的时间,可以揭示流程总提前期并帮助识别早期瓶颈。 获取方式 此 Event 是从 ReturnOrder 抬头的创建 timestamp 中捕获的。这通常可以在 SalesType 为“退货单”的 SalesTable 中找到。 捕获 SalesType = “Returned Order”的 SalesTable 记录的创建事件。 事件类型 explicit | |||
| 项目已接收 | 标记在仓库或指定退货中心物理接收到退回物品。这在与退货单关联的到货日记账过账时捕获。 | ||
| 为何重要 这是一个关键里程碑,标志着流程从客户操作转向内部处理。它是计算所有内部处理时间(如检验和处置)的起点。 获取方式 与 ReturnOrder 行关联的 WMS 日记账或商品到达日记账的过账 timestamp。这会将库存交易更新为“已登记”或“已收货”状态。 捕获 与退货单行关联的到货日记账的过账事件。 事件类型 explicit | |||
| 到货日记账已创建 | 此 Activity 表示仓库正等待退回商品到达。它涉及到达日记账的创建,为实物收货做好系统准备。 | ||
| 为何重要 此步骤将物流准备与实际物理收货分开,有助于分析仓库就绪情况并规划入库退货。 获取方式 在 WMSJournalTable 中创建 JournalType 为“Arrival”的记录。该日记账与退货单行关联。 捕获 该退货的 WMSJournalTable 记录的创建时间戳。 事件类型 explicit | |||
| 已创建换货订单 | 创建新的销售订单以向客户发送更换物品。当处置操作为“更换并退款”或“更换并报废”时,会发生此活动。 | ||
| 为何重要 此 Activity 启动了换货流程变体。将此路径与退款路径分开跟踪,对于理解换货的复杂性和成本至关重要。 获取方式 为换货商品创建新的 SalesTable 记录,通常是自动生成并关联至原始退货单。 捕获 通过处置操作创建与退货单关联的新销售订单。 事件类型 explicit | |||
| 更换件已发货 | 换货商品的装箱单已过账,表明已发货给客户。这标志着换货履行流程的完成。 | ||
| 为何重要 这是换货变体中的一个关键里程碑,代表公司履行了对客户的义务。对于跟踪换货周期时间至关重要。 获取方式 换货销售订单的装箱单日记账过账日期。这会将订单状态更新为“已交付”。 捕获 更换件销售订单的装箱单过账。 事件类型 explicit | |||
| 质量订单已生成 | 创建正式的质量订单,表示退回的物品必须经过结构化的检验流程。这常见于退货需要详细测试或对照质量标准进行检查的场景。 | ||
| 为何重要 此 Activity 标志着正式检验流程的开始。从此时点开始跟踪,有助于衡量质量保证 Workflow 的效率和持续时间。 获取方式 与退货单关联的 InventQualityOrderTable 记录的创建时间戳。 捕获 InventQualityOrderTable 记录的创建。 事件类型 explicit | |||
| 贷记通知单已创建 | 基于“退款”处置生成的贷方票据,授权向客户退款。这是流程中财务结算部分的正式开始。 | ||
| 为何重要 此 Activity 标志着财务退款的批准。从处置到贷记单创建之间的时间反映了发起退款时的行政延迟。 获取方式 这可以从创建具有负值的、关联至原始退货单的新 SalesTable 记录推断出,或通过运行“创建贷记单”批处理作业来识别。 捕获 创建贷方票据,通常通过过账退货单发票来完成。 事件类型 explicit | |||
| 退货单已取消 | 退货单在完成前被取消。这可能是由于客户要求,或者是商品从未退回。 | ||
| 为何重要 这代表了流程的一个非成功的替代终点。分析退货取消的原因可以深入了解客户行为或流程故障。 获取方式 根据 ReturnOrder 状态字段更改为“已取消”推断。这是与成功关闭订单不同的最终状态。 捕获 SalesTable.Status 字段更改为“已取消”。 事件类型 inferred | |||
| 退货单已确认 | 代表系统对退货单的正式确认,通常会触发后续业务逻辑。这通常记录为对 ReturnOrder 抬头的显式操作或状态更改。 | ||
| 为何重要 确认是物流开始前的关键步骤。创建与确认之间的延迟可能表明存在管理或系统相关的积压。 获取方式 这可以通过退货单的“确认”日记账过账或 SalesTable 中 DocumentStatus 字段的变更来识别。 捕获 执行退货单的“确认销售订单”功能。 事件类型 explicit | |||
提取指南
步骤
- 前提条件:在 Azure Active Directory 中注册应用程序。 在连接 Dynamics 365 API 之前,必须在 Azure AD 租户中注册一个应用程序。授予该程序访问 Dynamics 365 Finance & Operations 的委托权限,例如
Financials.ReadWrite.All或自定义权限。 - 在 Dynamics 365 中配置应用程序 ID。 导航至“系统管理 > 设置 > Azure Active Directory 应用程序”。添加 Azure AD 注册生成的应用程序(客户端)ID,并将其与拥有读取所需数据实体安全角色的用户账号关联。
- 获取 OAuth 2.0 访问令牌。 编写脚本(例如使用 PowerShell 或 Python)向 Microsoft 身份平台终结点进行身份验证。使用应用程序凭据(客户端 ID 和密钥)请求 Dynamics 365 资源 URL 的访问令牌。
- 识别您的 Dynamics 365 环境 URL。 找到 Dynamics 365 环境的基础 URL。Web API 终端通常如下所示:
https://[您的D365URL].dynamics.com/data。 - 构建并执行 OData API 请求。 针对 12 个必需的活动,分别构建特定的 OData GET 请求 URL。使用
$select仅检索必需的列,并使用$filter指定日期范围和状态条件。第 3 步获取的令牌必须作为 Bearer 令牌包含在每个请求的 Authorization 标头中。 - 开发提取脚本。 创建一个迭代处理 OData 请求列表的脚本。该脚本应负责身份验证、执行 GET 请求并存储返回的 JSON 数据。请注意 API 限制,必要时实施暂停机制。
- 处理 API 分页。 Dynamics 365 会对大数据结果进行分页。脚本必须检查响应中的
@odata.nextLink属性。如果存在,脚本需向该 URL 发起后续请求以检索下一页数据,直到不再提供nextLink为止。 - 转换并合并数据。 处理来自 12 个 API 调用的 JSON 响应。为每个活动创建一个包含
ReturnCaseId、ActivityName、EventTime及其他属性的标准化记录。例如,对于“Return Order Created”事件,将ReturnOrderNumber映射到ReturnCaseId,将ActivityName设为“Return Order Created”,并将createdDateTime映射到EventTime。最后将所有转换后的记录合并到一个列表或表中。 - 清理并标准化时间戳。 确保所有
EventTime值格式一致,建议使用 UTC 格式,如YYYY-MM-DDTHH:MM:SSZ。根据需要处理时间戳缺失或无效的记录。 - 导出最终事件日志。 所有数据收集并转换为统一数据集后,将其导出为 CSV 文件。确保列标题符合 ProcessMind 的要求:
ReturnCaseId、ActivityName、EventTime、ResponsibleUser、DispositionCode等。文件现在即可上传。
配置
- API 终端 URL: Dynamics 365 Finance & Operations 实例的基础 URL。格式通常为
https://[您的环境名称].dynamics.com/data。 - Azure AD 应用程序: 必须在 Azure AD 中注册一个包含客户端 ID 和密钥的应用程序。该程序需要具备访问 Dynamics 365 数据实体的 API 权限。
- 日期范围筛选: 这一点至关重要。在每次 API 调用中,请务必针对相关的日期字段(如
createdDateTime或modifiedDateTime),使用 OData 的$filter参数应用日期范围筛选。建议初始提取最近 3 到 6 个月的数据,以确保数据量可控。 - 公司筛选: 若要提取特定法律实体的数据,请包含
cross-company=true查询参数,并对dataAreaId字段使用$filter。例如:?cross-company=true&$filter=dataAreaId eq '[您的公司代码]'。 - 分页设置: 在请求头中使用
Prefer: odata.maxpagesize=[值]来控制每页返回的记录数。常用值为1000到5000,这有助于防止大型实体导致的 API 超时。 - API 限流: 请注意 Dynamics 365 API 的服务保护限制。数据提取脚本应包含处理
429 (Too Many Requests)响应的逻辑,通常建议实施指数级退避(exponential backoff)或简单的暂停重试机制。
a 查询示例 graphql
/*
This is a conceptual guide representing multiple, distinct OData API calls.
You will need a script (e.g., Python, PowerShell) to execute these calls sequentially,
authenticate with a bearer token, handle pagination, and union the results into a single file.
Replace [YourD365URL], [StartDate], [EndDate], and [YourCompanyCode] with your specific values.
*/
// Base URL for all requests
const string BaseUrl = "https://[YourD365URL].dynamics.com/data";
const string CompanyFilter = "?cross-company=true&$filter=dataAreaId eq '[YourCompanyCode]' and ";
const string DateFilterCreated = "createdDateTime ge [StartDate]T00:00:00Z and createdDateTime le [EndDate]T23:59:59Z";
const string DateFilterModified = "modifiedDateTime ge [StartDate]T00:00:00Z and modifiedDateTime le [EndDate]T23:59:59Z";
// 1. Return Order Created
GET {BaseUrl}/ReturnOrderHeaders{CompanyFilter}{DateFilterCreated}&$select=ReturnOrderNumber,createdDateTime,createdby,ReturnReasonCodeId
// Mapping: ReturnOrderNumber -> ReturnCaseId, 'Return Order Created' -> ActivityName, createdDateTime -> EventTime, createdby -> ResponsibleUser, ReturnReasonCodeId -> ReturnReasonCode
// 2. Return Order Confirmed
// This often updates the header status. We look for a modification time on confirmed orders.
GET {BaseUrl}/ReturnOrderHeaders{CompanyFilter}ReturnOrderStatus eq 'Confirmed' and {DateFilterModified}&$select=ReturnOrderNumber,modifiedDateTime,modifiedby,ReturnReasonCodeId
// Mapping: ReturnOrderNumber -> ReturnCaseId, 'Return Order Confirmed' -> ActivityName, modifiedDateTime -> EventTime, modifiedby -> ResponsibleUser
// 3. Arrival Journal Created
GET {BaseUrl}/WarehouseArrivalJournalHeaders{CompanyFilter}{DateFilterCreated}&$expand=WarehouseArrivalJournalLines($select=InventTransactionId)&$select=JournalNumber,createdDateTime,createdby
// Note: This requires post-processing to link JournalNumber to a ReturnCaseId via InventTransactionId.
// Mapping: Link via InventTrans -> ReturnCaseId, 'Arrival Journal Created' -> ActivityName, createdDateTime -> EventTime, createdby -> ResponsibleUser
// 4. Item Received (Arrival Journal Posted)
GET {BaseUrl}/WarehouseArrivalJournalHeaders{CompanyFilter}JournalPosted eq 'Yes' and {DateFilterModified}&$expand=WarehouseArrivalJournalLines($select=InventTransactionId)&$select=JournalNumber,modifiedDateTime,modifiedby
// Mapping: Link via InventTrans -> ReturnCaseId, 'Item Received' -> ActivityName, modifiedDateTime -> EventTime, modifiedby -> ResponsibleUser
// 5. Quality Order Generated
GET {BaseUrl}/InventQualityOrders{CompanyFilter}{DateFilterCreated}&$select=QualityOrderId,InventTransId,createdDateTime,CreatedByUserId,ItemId
// Mapping: Link via InventTransId -> ReturnCaseId, 'Quality Order Generated' -> ActivityName, createdDateTime -> EventTime, CreatedByUserId -> ResponsibleUser, ItemId -> ProductId
// 6. Disposition Code Applied
// This is a status change on the return line.
GET {BaseUrl}/ReturnOrderLines{CompanyFilter}ReturnDispositionCodeId ne '' and {DateFilterModified}&$select=ReturnOrderNumber,modifiedDateTime,modifiedby,ReturnDispositionCodeId,ItemId
// Mapping: ReturnOrderNumber -> ReturnCaseId, 'Disposition Code Applied' -> ActivityName, modifiedDateTime -> EventTime, modifiedby -> ResponsibleUser, ReturnDispositionCodeId -> DispositionCode, ItemId -> ProductId
// 7. Credit Note Created
// Look for sales orders with type 'Returned Order' that are not yet invoiced.
GET {BaseUrl}/SalesOrderHeadersV2{CompanyFilter}SalesOrderProcessingStatus eq 'Open' and SalesOrderType eq 'ReturnedOrder' and {DateFilterCreated}&$select=SalesOrderNumber,createdDateTime,createdby
// Mapping: SalesOrderNumber -> ReturnCaseId, 'Credit Note Created' -> ActivityName, createdDateTime -> EventTime, createdby -> ResponsibleUser
// 8. Credit Note Posted
// Look for posted invoice journals linked to a return order.
GET {BaseUrl}/SalesInvoiceJournalHeaders{CompanyFilter}SalesOrderType eq 'ReturnedOrder' and {DateFilterCreated}&$select=SalesOrderNumber,InvoiceDate,createdby
// Mapping: SalesOrderNumber -> ReturnCaseId, 'Credit Note Posted' -> ActivityName, InvoiceDate -> EventTime, createdby -> ResponsibleUser
// 9. Replacement Order Created
// Disposition code on the return line triggers a replacement order.
GET {BaseUrl}/SalesOrderHeadersV2{CompanyFilter}SalesOrderOriginType eq 'ReturnOrder' and {DateFilterCreated}&$select=SalesOrderNumber,createdDateTime,createdby,ReturnOrderNumber
// Mapping: ReturnOrderNumber -> ReturnCaseId, 'Replacement Order Created' -> ActivityName, createdDateTime -> EventTime, createdby -> ResponsibleUser
// 10. Replacement Item Shipped
// Check for posted packing slips related to the replacement sales order.
GET {BaseUrl}/SalesPackingSlipJournals{CompanyFilter}{DateFilterCreated}&$select=SalesOrderNumber,DeliveryDate,createdby
// Note: This requires linking SalesOrderNumber back to the original ReturnOrderNumber for the ReturnCaseId.
// Mapping: Link SalesOrderNumber -> ReturnCaseId, 'Replacement Item Shipped' -> ActivityName, DeliveryDate -> EventTime, createdby -> ResponsibleUser
// 11. Return Order Closed
GET {BaseUrl}/ReturnOrderHeaders{CompanyFilter}ReturnOrderStatus eq 'Closed' and {DateFilterModified}&$select=ReturnOrderNumber,modifiedDateTime,modifiedby
// Mapping: ReturnOrderNumber -> ReturnCaseId, 'Return Order Closed' -> ActivityName, modifiedDateTime -> EventTime, modifiedby -> ResponsibleUser
// 12. Return Order Cancelled
GET {BaseUrl}/ReturnOrderHeaders{CompanyFilter}ReturnOrderStatus eq 'Canceled' and {DateFilterModified}&$select=ReturnOrderNumber,modifiedDateTime,modifiedby
// Mapping: ReturnOrderNumber -> ReturnCaseId, 'Return Order Cancelled' -> ActivityName, modifiedDateTime -> EventTime, modifiedby -> ResponsibleUser 步骤
- 启用 TDS 终端: 确保您的 Dynamics 365 Dataverse 环境已启用表格式数据流 (TDS) 终端。系统管理员可以在 Power Platform 管理中心的“环境 > 设置 > 功能”中启用此功能。
- 识别环境 URL: 找到您的环境 URL。通常格式为
yourorg.crm.dynamics.com。TDS 终端服务器名称将为此 URL 加上端口 5558,例如:yourorg.crm.dynamics.com,5558。 - 使用 SQL 客户端连接: 使用支持 TDS 的 SQL 客户端,如 SQL Server Management Studio (SSMS) 或 Azure Data Studio。
- 身份验证: 使用拥有适当权限(通常是 Dataverse 环境中的系统管理员或系统自定义员)的 Azure Active Directory 账号连接到服务器。
- 准备查询: 将本文档
query部分提供的完整 SQL 查询语句复制到 SQL 客户端的新查询窗口中。 - 设置参数: 在查询中找到占位符。将
'{StartDate}'和'{EndDate}'替换为您希望提取的日期范围,例如'2023-01-01'和'2023-12-31'。同时,根据您的 Dynamics 365 具体配置,更新状态代码或处置代码的占位符数值。 - 执行查询: 针对 Dataverse 数据库运行修改后的查询。执行时间取决于数据量和所选日期范围。
- 查看结果: 查询完成后,检查返回的数据集,确保包含以下必需列:
ReturnCaseId、ActivityName、EventTime以及推荐的属性列。 - 导出事件日志: 将查询结果导出为 CSV 文件。大多数 SQL 客户端都有内置功能将结果直接保存到文件。请确保文件保存为 UTF-8 编码。
- 上传至 ProcessMind: 导出的 CSV 文件现在即可作为新的事件日志上传到 ProcessMind,进行流程挖掘分析。
配置
- 前提条件: 您必须拥有一个至少具备相关 Dataverse 表(如 SalesTable、SalesLine、CustInvoiceJour)读取权限的用户账号。权限通常通过“系统管理员”等安全角色或具有充足表权限的自定义角色进行管理。
- TDS 终端: 必须为该环境启用 Dataverse TDS 终端。此功能允许直接针对 Dataverse 数据库执行只读 SQL 查询。
- 日期范围: 查询语句包含
'{StartDate}'和'{EndDate}'占位符。为了在不影响性能的情况下获得具有代表性的数据集,建议初始分析选择 3 到 6 个月的日期范围。 - 公司筛选: 当前编写的查询将跨用户有权访问的所有法律实体(公司)运行。如需针对单一公司进行分析,请取消注释并在每个
UNION ALL语句中添加针对DATAAREAID字段的WHERE过滤子句,例如:AND st.DATAAREAID = '[您的公司 ID]'。 - 自定义逻辑占位符: 查询中包含诸如
[YourReplaceCode1]之类的占位符,用于处置代码和关联替换订单的注释。这些必须根据您的具体业务流程和 Dynamics 365 设置进行配置。 - 性能: 针对大数据集直接查询 TDS 终端可能会较慢。虽然该连接已针对分析查询进行了优化,但跨数百万行的复杂联接仍可能超时。建议应用严格的日期筛选。
a 查询示例 sql
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Return Order Created' AS ActivityName,
st.CREATEDDATETIME AS EventTime,
st.CREATEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Return Order Confirmed' AS ActivityName,
st.MODIFIEDDATETIME AS EventTime,
st.MODIFIEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.DOCUMENTSTATUS = 1 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Arrival Journal Created' AS ActivityName,
wjt.CREATEDDATETIME AS EventTime,
wjt.CREATEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
JOIN WMSJOURNALTABLE wjt ON st.SALESID = wjt.ORDERID AND st.DATAAREAID = wjt.DATAAREAID
WHERE st.SALESTYPE = 3 AND wjt.JOURNALTYPE = 4 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Item Received' AS ActivityName,
wjt.POSTEDDATETIME AS EventTime,
wjt.POSTEDUSERID AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
JOIN WMSJOURNALTABLE wjt ON st.SALESID = wjt.ORDERID AND st.DATAAREAID = wjt.DATAAREAID
WHERE st.SALESTYPE = 3 AND wjt.JOURNALTYPE = 4 AND wjt.POSTEDDATETIME IS NOT NULL AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Quality Order Generated' AS ActivityName,
iqot.CREATEDDATETIME AS EventTime,
iqot.CREATEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
iqot.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
JOIN INVENTQUALITYORDERTABLE iqot ON sl.INVENTTRANSID = iqot.INVENTTRANSID AND sl.DATAAREAID = iqot.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Disposition Code Applied' AS ActivityName,
iqot.VALIDATEDDATETIME AS EventTime,
iqot.VALIDATEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
iqot.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
JOIN INVENTQUALITYORDERTABLE iqot ON sl.INVENTTRANSID = iqot.INVENTTRANSID AND sl.DATAAREAID = iqot.DATAAREAID
WHERE st.SALESTYPE = 3 AND iqot.VALIDATEDDATETIME IS NOT NULL AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Credit Note Created' AS ActivityName,
st.MODIFIEDDATETIME AS EventTime,
st.MODIFIEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.SALESSTATUS = 3 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Credit Note Posted' AS ActivityName,
cij.CREATEDDATETIME AS EventTime,
cij.CREATEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
JOIN CUSTINVOICEJOUR cij ON st.SALESID = cij.SALESID AND st.DATAAREAID = cij.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
ro.RETURNITEMNUM AS ReturnCaseId,
'Replacement Order Created' AS ActivityName,
replacement_so.CREATEDDATETIME AS EventTime,
replacement_so.CREATEDBY AS ResponsibleUser,
NULL AS DispositionCode,
NULL AS ReturnReasonCode,
replacement_so.SALESORIGINID AS ReturnChannel,
replacement_sl.ITEMID AS ProductId
FROM SALESTABLE ro
JOIN SALESLINE rol ON ro.SALESID = rol.SALESID AND ro.DATAAREAID = rol.DATAAREAID
JOIN SALESTABLE replacement_so ON ro.CUSTACCOUNT = replacement_so.CUSTACCOUNT AND ro.DATAAREAID = replacement_so.DATAAREAID
JOIN SALESLINE replacement_sl ON replacement_so.SALESID = replacement_sl.SALESID AND replacement_so.DATAAREAID = replacement_sl.DATAAREAID
WHERE ro.SALESTYPE = 3
AND rol.RETURNDISPOSITIONCODEID IN ('[YourReplaceCode1]', '[YourReplaceCode2]')
AND replacement_so.SALESTYPE = 1
AND replacement_so.CREATEDDATETIME > ro.CREATEDDATETIME
-- The join above is a basic example and must be replaced with your system's specific logic for linking returns to replacements.
AND ro.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
ro.RETURNITEMNUM AS ReturnCaseId,
'Replacement Item Shipped' AS ActivityName,
cpsj.CREATEDDATETIME AS EventTime,
cpsj.CREATEDBY AS ResponsibleUser,
NULL AS DispositionCode,
NULL AS ReturnReasonCode,
replacement_so.SALESORIGINID AS ReturnChannel,
cpsl.ITEMID AS ProductId
FROM SALESTABLE ro
JOIN SALESLINE rol ON ro.SALESID = rol.SALESID AND ro.DATAAREAID = rol.DATAAREAID
JOIN SALESTABLE replacement_so ON ro.CUSTACCOUNT = replacement_so.CUSTACCOUNT AND ro.DATAAREAID = replacement_so.DATAAREAID
JOIN CUSTPACKINGSLIPJOUR cpsj ON replacement_so.SALESID = cpsj.SALESID AND replacement_so.DATAAREAID = cpsj.DATAAREAID
JOIN CUSTPACKINGSLIPTRANS cpsl ON cpsj.PACKINGSLIPID = cpsl.PACKINGSLIPID AND cpsj.SALESID = cpsl.SALESID AND cpsj.DATAAREAID = cpsl.DATAAREAID
WHERE ro.SALESTYPE = 3
AND rol.RETURNDISPOSITIONCODEID IN ('[YourReplaceCode1]', '[YourReplaceCode2]')
AND replacement_so.SALESTYPE = 1
AND replacement_so.CREATEDDATETIME > ro.CREATEDDATETIME
-- The join above is a basic example and must be replaced with your system's specific logic for linking returns to replacements.
AND ro.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Return Order Closed' AS ActivityName,
st.MODIFIEDDATETIME AS EventTime,
st.MODIFIEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.SALESSTATUS = 3 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
SELECT
st.RETURNITEMNUM AS ReturnCaseId,
'Return Order Cancelled' AS ActivityName,
st.MODIFIEDDATETIME AS EventTime,
st.MODIFIEDBY AS ResponsibleUser,
sl.RETURNDISPOSITIONCODEID AS DispositionCode,
sl.RETURNREASONCODEID AS ReturnReasonCode,
st.SALESORIGINID AS ReturnChannel,
sl.ITEMID AS ProductId
FROM SALESTABLE st
JOIN SALESLINE sl ON st.SALESID = sl.SALESID AND st.DATAAREAID = sl.DATAAREAID
WHERE st.SALESTYPE = 3 AND st.SALESSTATUS = 4 AND st.CREATEDDATETIME BETWEEN '{StartDate}' AND '{EndDate}';