microsoft / microsoft/BCApps

[Bug][Subscription Billing] "Delete Invoiced Sales Orders" leaves orphaned Sales Subscription Lines behind

Open
#10,175 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Approved Ownership: Manual Team: Finance
Dominant language
AL
Stars
683
Forks
459
Avg merge
3d 26m
Merged PRs (30d)
633

Description

Describe the issue

When a fully invoiced sales order is removed with the standard Delete Invoiced Sales Orders batch job, the Subscription Billing data attached to that order is not removed with it. The order and its lines disappear, but the Sales Subscription Lines that belonged to those order lines stay in the database and become orphaned records: they still point to a document number that no longer exists.

Users notice this on the Sales Subscription Lines list, which keeps growing with entries for orders nobody can open any more. Nothing in the UI can clean them up, because the document they belong to is gone — the only way to get rid of them is a data fix.

The same cleanup works correctly when an order is deleted manually from the Sales Orders list, or when a quote is converted into an order, so the leftovers only appear for orders that were removed by this batch job. That makes the problem easy to miss and it accumulates silently over time.

Expected behavior

Deleting a sales order through report 299 "Delete Invoiced Sales Orders" should delete the related records in table 8068 "Sales Subscription Line", exactly as every other deletion path already does. No record in table 8068 should survive the document it belongs to.

Cause

Subscription Billing cleans up table 8068 in the OnDelete() trigger of tableextension 8054 "Sales Line" (DeleteSalesServiceCommitment()). Report 299 deletes the order lines and the header without running triggers:

SalesOrderLine.Delete();          // Base Application, report 299, line ~103
...
Delete();                         // the Sales Header, line ~137

Because Delete() defaults to RunTrigger = false, the table extension trigger never fires and the Sales Subscription Lines are left behind.

The app already handles the other trigger-less deletion paths with subscribers in codeunit "Sales Subscription Line Mgmt.":

  • Codeunit::"Sales-Post", OnBeforeSalesLineDeleteAllDeleteSalesServiceCommitmentOnBeforeSalesLineDeleteAll
  • Codeunit::"Sales-Quote to Order", OnRunOnAfterSalesQuoteLineDeleteAllDeleteSalesServiceCommitmentOnAfterSalesQuoteLineDeleteAll

Report 299 is the one that is missing.

Proposed fix

Report 299 already raises a suitable integration event after each deleted line, so no base application change is needed. Add a subscriber to codeunit "Sales Subscription Line Mgmt.":

[EventSubscriber(ObjectType::Report, Report::"Delete Invoiced Sales Orders", OnAfterDeleteSalesLine, '', false, false)]
local procedure DeleteSalesSubscriptionLinesOnAfterDeleteSalesLine(var SalesLine: Record "Sales Line")
begin
    SalesLine.DeleteSalesServiceCommitment();
end;

DeleteSalesServiceCommitment() already guards against temporary records and against document types that cannot carry subscription lines, so it is safe to call for every deleted line.

An alternative, broader fix is a subscriber to Database::"Sales Line", OnAfterDeleteEvent guarded with if RunTrigger then exit;, which would also catch any other caller that deletes sales lines without triggers. The narrow, report-specific subscriber is preferred because it keeps the existing per-path pattern of the app and cannot change behaviour of unrelated deletion paths.

Archiving is not affected: the report archives the document before deleting it, so the "Sales Subscription Line Archive" entries are written correctly. Only the live table 8068 leaks.

There is currently no test covering report 299 in the Subscription Billing test app; the fix should come with a test that runs the report on a fully invoiced order and asserts that no "Sales Subscription Line" remains for that document.

Steps to reproduce
  1. Create an item and set Subscription Option = Service Commitment Item, then assign a subscription package to it.
  2. Create a sales order for a customer and add one line with that item. On the line, choose Line > Subscription Lines and confirm that Sales Subscription Lines were created for it.
  3. Post the order with Ship and Invoice. The order is fully shipped and invoiced but stays in the Sales Orders list.
  4. Search for Delete Invoiced Sales Orders, filter on the order number from step 2 and run the batch job.
  5. Confirm the order is gone from the Sales Orders list.
  6. Search for Sales Subscription Lines and filter Document No. on the deleted order number.

Result: the Sales Subscription Lines of the deleted order are still there and can no longer be reached from any document.

Expected: the list is empty — the subscription lines were deleted together with the order.

Additional context

No response

I will provide a fix for a bug
  • I will provide a fix for a bug

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with report 299, "Delete Invoiced Sales Orders", and codeunit "Sales Subscription Line Mgmt."; compare its existing Sales-Post and Sales-Quote to Order subscribers with the report's OnAfterDeleteSalesLine event. Add coverage in the Subscription Billing test app by running the report on a fully invoiced order and verifying that no table 8068 "Sales Subscription Line" remains for the deleted document.

Written by the indexing model from the issue text.

Assessment

Domain
backend, databases, testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.