Undo of posted subcontracting purchase receipt fails with duplicate Item Entry Relation key
Nobody has claimed this yet.
- Dominant language
- AL
- Stars
- 683
- Forks
- 459
- Avg merge
- 3d 26m
- Merged PRs (30d)
- 633
Description
Summary
When undoing a posted subcontracting purchase receipt, Business Central can fail with a duplicate-key error while inserting an Item Entry Relation record. In cases where no key collision happens, the undo can silently insert an incorrect relation.
Repro / Affected scenario
Undo a posted subcontracting purchase receipt where the output is tracked or involves more than one output entry, specifically when any of the following apply:
- Multiple eligible output Item Ledger Entries exist for the receipt.
- The single output entry is lot-tracked.
- The single output entry is serial-tracked.
Partial subcontracting receipts are a likely reproducer because they can produce the above entry topology, but are not a strict prerequisite.
Found in build 28.3.
Expected result
Undoing the subcontracting purchase receipt completes successfully, and any Item Entry Relation created during the undo references the correct reversing Item Ledger Entry.
Actual result
The undo fails with a duplicate primary key error when inserting into table 6507 Item Entry Relation. When no collision occurs, the undo may succeed but store an Item Entry No. that does not identify the newly posted reversing Item Ledger Entry, leaving item tracking associated with the wrong entry.
Root cause
Table 6507 Item Entry Relation uses Item Entry No. as its clustered primary key and defines it as a relation to Item Ledger Entry. During subcontracting undo, this key is populated with a Capacity Ledger Entry number instead of an Item Ledger Entry number.
The faulty data flow:
- Subcontracting setup –
MfgUndoPurchRcptLinemarks the item journal line as subcontracting. The single-entry shortcut is used only when exactly one output item ledger entry exists and it has neither lot nor serial tracking. Tracked or multiple output entries take the applied-entry-list path. - Overloaded return value – For subcontracting,
Item Jnl.-Post Line(codeunit 22) deliberately returns the Capacity Ledger Entry number throughItemJnlLine."Item Shpt. Entry No.". Normal item posting returns the actual Item Ledger Entry number in that field. - Type/contract confusion – On the applied-entry-list path,
PostItemJnlLineAppliedToList()inUndoPostingManagementtreatsItem Shpt. Entry No.as an Item Ledger Entry number and copies it intoTempItemEntryRelation."Item Entry No.". - Duplicate insert –
UndoPurchaseReceiptLinetransfers the temporary row to table 6507 with an unconditionalInsert(). Nothing converts the capacity entry number into the posted output Item Ledger Entry number.
Because capacity ledger entries and item ledger entries use independent number sequences, the failure is intermittent: the duplicate-key error surfaces only when the newly generated capacity entry number already exists as an Item Entry Relation primary key. When there is no collision, the invalid relation is inserted silently (AL TableRelation is not a database foreign-key constraint, so it does not guarantee referential correctness on insert).
Fix direction
The relation must be populated with the reversing output Item Ledger Entry."Entry No." produced by the specific posting iteration, not the Capacity Ledger Entry number and not the original entry being reversed (TempApplyToItemLedgEntry."Entry No.").
Replacing the subcontracting return value globally is unsafe, because manufacturing posting legitimately reads Item Shpt. Entry No. as a Capacity Ledger Entry reference. Safer approaches:
- Return the new Item Ledger Entry number separately from the capacity entry number.
- Expose the posted reversing Item Ledger Entry number explicitly from codeunit 22.
- Avoid deriving it from sequence state or a "last entry" lookup, especially under modern number allocation and concurrency.
Test coverage gap
The existing subcontracting test UndoPurchaseReceiptForLastOperation uses a single, untracked output entry and therefore takes the single-entry shortcut, which does not exercise the faulty relation insertion. There is no test that combines undo with tracked or multiple output entries. A regression test should cover a tracked or multi-output undo with a pre-existing relation key matching the next capacity entry number.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with MfgUndoPurchRcptLine and the applied-entry path in PostItemJnlLineAppliedToList() in UndoPostingManagement, then trace Item Jnl.-Post Line (codeunit 22) through UndoPurchaseReceiptLine. Compare the existing UndoPurchaseReceiptForLastOperation test with a tracked or multi-output undo. Done means the regression test covers the relation-key collision and the created Item Entry Relation points to the reversing Item Ledger Entry.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend, databases, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100