返回 Skill 列表
extension
分类: 开发与工程无需 API Key

d365fo-debugging

完整的D365 Finance & Operations调试框架。将症状路由到正确的剧本(财务、SCM、WMS、批处理、安全、集成、性能、报告)。激活用于D365、Dynamics、AX、凭证、过账、批处理作业、SSRS、DMF、工单、波次、安全、无法过账、缺失、金额错误、缓慢、卡住。

person作者: jakexiaohubgithub

D365 Finance & Operations - Complete Debugging Framework v6

FORENSICS CORE (The Kernel)

These rules apply to EVERY playbook, EVERY time.

Anti-Hallucination Rules (NEVER violate)

| Rule | Description | |------|-------------| | SCHEMA FIRST | NEVER guess columns. Run SELECT TOP 1 * or sys.columns before any filtered query | | NO HARD-CODED FILTERS | NEVER hard-code DATAAREAID, PARTITION, or database names without validation | | PLATINUM RULE | ALWAYS find a WORKING example and DIFF it. 2 queries beats 15 | | DIAMOND RULE | Check FULL STACK: UI/Form -> Business Logic -> Config -> Batch/Report/Integration | | LINE CONTAMINATION | One bad LINE can override the entire HEADER classification | | STOP CONDITIONS | If not found after 3 queries -> pivot upstream/downstream |

Universal Inputs

REQUIRED (at least one):
- businessKey: The document/record ID (SO number, PO, Invoice, Voucher, WorkId, etc.)
- symptom: What's wrong (missing, wrong amount, can't post, slow, etc.)

OPTIONAL (validate before using):
- legalEntity / company / DATAAREAID
- partition
- environment (DEV/UAT/PROD)
- user (who experienced it)
- timeWindow (when it happened)
- documentType (SalesOrder, PurchaseOrder, TransferOrder, Invoice, etc.)
- journalType (AP/AR/GL/FA)
- reportName / menuItemName
- batchJobId / batchTaskId
- dataEntityName / integrationName
- errorMessage (exact text)
- correlationId (for integrations)

Standard Output Format (Every Run)

## D365 Debug: [Symptom] - [BusinessKey]

### 1. Assumptions
- Assuming: [What I'm taking as given]
- NOT assuming: [What I'll verify]
- Routing to: [Playbook name]

### 2. First 3 Safe Checks (Schema-First)
1. [Schema discovery query]
2. [Existence check]
3. [State/status check]

### 3. Platinum Diff Plan
- Good reference: [How to find one]
- Diff query: [Compare bad vs good]

### 4. Diamond Stack Trace
- UI/Form layer: [What to check]
- Business logic: [Classes/methods]
- Configuration: [Setup tables]
- Execution layer: [Batch/report/integration]

### 5. Stop Conditions
- If [X] not found -> Pivot to [Y]
- If data correct but excluded -> Check [Z]

### 6. Resolution
[What fixed it or next steps]

SYMPTOM ROUTER

Start here. Match symptom to playbook:

| Symptom Pattern | Route To | First Check | |-----------------|----------|-------------| | "Missing from report" | REPORTING | Data exists? -> DP class filter | | "Not posted / can't post" | POSTING | Validation errors -> Setup -> Workflow | | "Wrong amount / calculation" | FINANCE-CALC | Platinum diff -> Line contamination | | "User can't see / access" | SECURITY | Entry point -> Role -> Privilege | | "Integration success but no record" | INTEGRATION | Staging -> Entity mapping -> Business events | | "Batch didn't run / stuck" | BATCH | History -> Dependencies -> Batch group | | "Slow / hanging / timeout" | PERFORMANCE | Locks -> SQL plan -> AOS load | | "Invoice missing lines" | SCM-ORDER | SO/PO lines -> Packing slip -> Invoice match | | "Work stuck / not released" | WMS | Wave -> Work -> Location directives | | "Voucher wrong / missing" | FINANCE-GL | Journal -> Posting profile -> Dimensions |


CAPABILITY PACK: FINANCE

GL (General Ledger)

Key identifiers: Voucher, JournalNum, AccountingDate, MainAccount

Canonical lineage:

LedgerJournalTable (header)
  -> LedgerJournalTrans (lines)
    -> GeneralJournalEntry (posted)
      -> GeneralJournalAccountEntry (account splits)

Schema discovery:

SELECT TOP 1 * FROM LedgerJournalTable;
SELECT TOP 1 * FROM GeneralJournalEntry;

Common contaminators:

  • Wrong posting profile on line
  • Dimension mismatch (MainAccount vs DefaultDimension)
  • Currency/exchange rate at line level
  • Blocked account or suspended dimension

Voucher prefix decoder: | Prefix | Source | Trace To | |--------|--------|----------| | INT | External integration | Staging table | | INV | AP Invoice | VendInvoiceJour | | PAY | Payment | VendPaymJournalTrans | | GJ | GL Journal | LedgerJournalTrans | | CXI | Customer Invoice | CustInvoiceJour |

AP (Accounts Payable)

Key identifiers: InvoiceId, VendAccount, Voucher, PurchId

Canonical lineage:

VendInvoiceInfoTable (pending)
  -> VendInvoiceInfoLine
    -> VendInvoiceJour (posted header)
      -> VendInvoiceTrans (posted lines)
        -> VendTrans (subledger)
          -> GeneralJournalEntry (GL)

Common issues:

-- Invoice not posting: Check validation
SELECT * FROM VendInvoiceInfoTable
WHERE ParmId = 'INVOICE_ID' AND Posted = 0;

-- Match failures
SELECT PurchId, InvoiceId, MatchStatus, MatchVariance
FROM VendInvoiceInfoTable
WHERE InvoiceAccount = 'VENDOR';

AR (Accounts Receivable)

Key identifiers: InvoiceId, CustAccount, SalesId, Voucher

Canonical lineage:

SalesTable -> SalesLine
  -> CustPackingSlipJour -> CustPackingSlipTrans
    -> CustInvoiceJour -> CustInvoiceTrans
      -> CustTrans -> GeneralJournalEntry

CAPABILITY PACK: SUPPLY CHAIN (SCM)

Order-to-Cash

Key identifiers: SalesId, ItemId, InventTransId

Canonical lineage:

SalesTable (header)
  -> SalesLine (lines)
    -> InventTrans (inventory transactions)
      -> CustPackingSlipJour/Trans (packing slip)
        -> CustInvoiceJour/Trans (invoice)

Missing invoice lines check:

-- Compare SO lines to invoice lines
SELECT
    SL.SalesId, SL.ItemId, SL.LineNum,
    SL.SalesQty AS OrderedQty,
    ISNULL(IT.InvoicedQty, 0) AS InvoicedQty
FROM SalesLine SL
LEFT JOIN (
    SELECT InventTransId, SUM(Qty) AS InvoicedQty
    FROM CustInvoiceTrans
    GROUP BY InventTransId
) IT ON SL.InventTransId = IT.InventTransId
WHERE SL.SalesId = 'SO_NUMBER'
  AND SL.SalesQty <> ISNULL(IT.InvoicedQty, 0);

Procure-to-Pay

Key identifiers: PurchId, ItemId, InventTransId

Canonical lineage:

PurchTable -> PurchLine
  -> InventTrans
    -> VendPackingSlipJour/Trans (product receipt)
      -> VendInvoiceJour/Trans (invoice)

Inventory

Key identifiers: ItemId, InventDimId, InventTransId

On-hand investigation:

-- Current on-hand
SELECT ItemId, InventDimId, PhysicalInvent, AvailPhysical
FROM InventSum
WHERE ItemId = 'ITEM';

-- Transaction history
SELECT * FROM InventTrans
WHERE ItemId = 'ITEM'
ORDER BY DatePhysical DESC;

CAPABILITY PACK: WAREHOUSE (WMS)

Key identifiers: WorkId, LoadId, ShipmentId, WaveId, WHSContainerId

Canonical lineage:

WHSWave
  -> WHSLoadTable -> WHSLoadLine
    -> WHSWorkTable -> WHSWorkLine
      -> WHSContainerTable
        -> WHSWorkInventTrans

Work stuck diagnosis:

-- Work status check
SELECT WorkId, WorkStatus, TargetLicensePlateId,
       CreateDateTime, UserId
FROM WHSWorkTable
WHERE LoadId = 'LOAD_ID';

-- Wave status
SELECT WaveId, WaveStatus, WaveProcessed
FROM WHSWave
WHERE WaveId = 'WAVE_ID';

Common issues:

  • Location directive not finding put location
  • Work template missing lines
  • Reservation not available
  • License plate conflicts

Location directive debug:

SELECT * FROM WHSLocDirTable
WHERE WorkType = 1  -- Put
  AND WorkTransType = 1  -- Sales
ORDER BY SeqNum;

CAPABILITY PACK: BATCH & OPERATIONS

Key identifiers: BatchJobId, Caption, Status, StartDateTime

Batch job diagnosis:

-- Job history
SELECT TOP 20
    RecId, Caption, Status,
    StartDateTime, EndDateTime,
    CreatedBy, AlertsProcessed
FROM BatchJob
WHERE Caption LIKE '%JOB_NAME%'
ORDER BY StartDateTime DESC;

-- Status decoder
-- 0=Hold, 1=Waiting, 2=Executing, 3=Error, 4=Finished, 5=Canceling

-- Stuck tasks
SELECT BJ.Caption, BT.ClassNumber, BT.Status, BT.Info
FROM BatchJob BJ
JOIN BatchTask BT ON BJ.RecId = BT.BatchJobId
WHERE BJ.Status = 2  -- Executing
  AND BJ.StartDateTime < DATEADD(hour, -2, GETDATE());

Why didn't it run?

  1. Check BatchJob.Status - is it on Hold (0)?
  2. Check BatchGroup assignment - is AOS in the group?
  3. Check dependencies - BatchConstraints table
  4. Check recurrence - BatchJob.RecurrenceData
  5. Check BatchServerGroup - is batch server enabled?

CAPABILITY PACK: SECURITY

Key identifiers: UserId, SecurityRole, MenuItemName

"User can't see/do X" diagnosis:

-- 1. What roles does user have?
SELECT SR.Name AS RoleName, URS.AssignmentMode
FROM SecurityUserRole URS
JOIN SecurityRole SR ON URS.SecurityRole = SR.RecId
WHERE URS.User = 'USER_ID';

-- 2. What entry point is needed?
SELECT * FROM SecurableObject
WHERE Name = 'MENU_ITEM_NAME';

-- 3. Which roles have that entry point?
SELECT DISTINCT SR.Name AS RoleName
FROM SecurityRole SR
JOIN SecurityRolePermission SRP ON SR.RecId = SRP.SecurityRole
JOIN SecurableObject SO ON SRP.SecurableObject = SO.RecId
WHERE SO.Name = 'MENU_ITEM_NAME';

Stack trace:

Menu Item (entry point)
  -> Security Privilege (atomic permission)
    -> Security Duty (job function)
      -> Security Role (assigned to user)

Common issues:

  • Role assigned but duty excluded
  • Data security policy filtering out records
  • Privilege exists but grant type is Deny
  • Legal entity restriction on role

CAPABILITY PACK: INTEGRATION (DMF/OData)

Key identifiers: ExecutionId, EntityName, DefinitionGroupId

DMF import diagnosis:

-- Execution history
SELECT TOP 20
    ExecutionId, DefinitionGroupId, StartTime, EndTime,
    StagingStatus, TargetStatus, ErrorCount
FROM DMFExecutionSummary
WHERE DefinitionGroupId = 'PROJECT_NAME'
ORDER BY StartTime DESC;

-- Staging table errors
SELECT * FROM [STAGING_TABLE]
WHERE DefinitionGroup = 'PROJECT'
  AND TransferStatus = 2;  -- Error

-- Error details
SELECT ExecutionId, Field, ErrorCode, ErrorMessage
FROM DMFExecutionErrors
WHERE ExecutionId = 'EXEC_ID';

"Success but no record" diagnosis:

  1. Check staging table - did data land?
  2. Check TransferStatus - did it process?
  3. Check entity mapping - field mappings correct?
  4. Check target table - record exists but different key?
  5. Check business validation - rejected by entity logic?

Integration lineage:

Source File/API
  -> DMF Staging Table (raw data)
    -> DMF Execution (processing)
      -> Target Table (final data)
        -> Business Events (if configured)

CAPABILITY PACK: REPORTING (SSRS)

Key identifiers: ReportName, DesignName, MenuItemName

CRITICAL: Logic is in Data Provider (DP), NOT Controller!

Controller Class: Parameters, dialog, print destination
  -> DP Class (*DP): Query building, data population
    -> TMP Table (*Tmp): Holds processed data
      -> SSRS Design: Rendering only

Report not showing records diagnosis:

-- 1. Does data exist?
SELECT TOP 10 * FROM [SourceTable]
WHERE [Filter] = 'VALUE';

-- 2. Find the DP class
-- Look for [ReportName]DP in AOT

-- 3. Check DP.processReport() method
-- Look for QueryRun, while select, insertTmp()

Common issues:

  • Query range in DP excludes records
  • Print management setup missing
  • Report parameters not passed to DP
  • TMP table insert logic has additional filters

CAPABILITY PACK: PERFORMANCE

Key identifiers: SPID, WaitType, QueryHash

Blocking/locking diagnosis:

-- Current blocks
SELECT
    blocking.session_id AS BlockingSession,
    blocked.session_id AS BlockedSession,
    blocked.wait_type,
    blocked.wait_time,
    OBJECT_NAME(locked.object_id) AS LockedTable
FROM sys.dm_exec_requests blocked
JOIN sys.dm_exec_sessions blocking ON blocked.blocking_session_id = blocking.session_id
JOIN sys.dm_tran_locks locked ON blocked.session_id = locked.request_session_id;

-- Long running queries
SELECT TOP 10
    r.session_id,
    r.start_time,
    r.status,
    SUBSTRING(t.text, 1, 200) AS QueryText
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.status = 'running'
ORDER BY r.total_elapsed_time DESC;

Missing indexes:

SELECT TOP 20
    OBJECT_NAME(mid.object_id) AS TableName,
    mid.equality_columns,
    mid.inequality_columns,
    migs.user_seeks,
    migs.avg_user_impact
FROM sys.dm_db_missing_index_details mid
JOIN sys.dm_db_missing_index_groups mig ON mid.index_handle = mig.index_handle
JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle
ORDER BY migs.user_seeks * migs.avg_user_impact DESC;

TEST PROMPTS (Validate Coverage)

Use these to verify the skill works:

  1. Finance: "Voucher INT-123456 exists but amount is wrong"
  2. SCM: "Sales order SO-001234 invoice missing 3 lines"
  3. WMS: "Work ID 5678 created but stuck, not releasing"
  4. Batch: "Vendor invoice posting batch didn't run last night"
  5. Security: "User JSMITH can't see Post button on vendor invoice"
  6. Integration: "DMF import shows success but no purchase orders created"

KEY PRINCIPLE

Don't debug blind. ROUTE -> SCHEMA -> PLATINUM -> DIAMOND -> PIVOT.

The symptom tells you WHERE to look. The working example tells you WHAT's wrong.