BizCentralOrbit

Can We Delete Posted Documents in Business Central?

Yes, we can delete these documents by customization. In Microsoft Dynamics 365 Business Central, posted documents and ledger entries are normally protected and cannot be deleted directly. This behavior is intentional, as Business Central is designed to preserve financial accuracy, audit integrity, and historical transaction data. However, in some business scenarios, organizations may need a controlled way to remove specific posted records through customization.

In this blog, we are discussing a practical requirement where the system needs to delete records from multiple posted and ledger tables, such as G/L Entry, Posted G/L Entry, Posted Sales Invoice, Posted Sales Shipment, Posted Purchase Invoice, Posted Purchase Receipt, Posted Transfer Shipment, and Posted Transfer Receipt. To handle this requirement, we create a setup table with a Deletion Date field. When a user enters a date in this field, the system applies a filter on the related tables and deletes all records up to that selected date.

This approach gives us a controlled and structured way to manage deletion through AL customization, instead of deleting records manually one by one. It also helps developers understand how to build a reusable setup-based solution that can be extended for different posted tables and business rules. We will first design the Codeunit, and once it is ready, we will assign the appropriate permissions to ensure it functions correctly within the system.

Permissions =
     tabledata "Sales Invoice Line" = RIMD,
     tabledata "Sales Invoice Header" = RIMD,
     tabledata "Sales Comment Line" = RIMD,
     tabledata "Sales Shipment Line" = RIMD,
     tabledata "Sales Shipment Header" = RIMD,
     tabledata "Purch. Inv. Line" = RIMD,
     tabledata "Purch. Inv. Header" = RIMD,
     tabledata "Purch. Comment Line" = RIMD,
     tabledata "Purch. Rcpt. Line" = RIMD,
     tabledata "Purch. Rcpt. Header" = RIMD,
     tabledata "G/L Entry" = RIMD,
     tabledata "Transfer Receipt Header" = RIMD,
     tabledata "Transfer Receipt Line" = RIMD,
     tabledata "Transfer Shipment Header" = RIMD,
    tabledata "Transfer Shipment Line" = RIMD,
     tabledata "Inventory Comment Line" = RIMD,
     tabledata "Posted Gen. Journal Line" = RIMD;

Below are the procedures which we used to delete records in codeunit.

trigger OnRun()

    begin
        GLEntryDelete();
        PostedGLEntryDelete();
        SalesInvoiceLineHeaderDelete();
        SalesShipLineHeaderDelete();
        PurchaseInvoiceLineHeaderDelete();
        PurchaseReceiptDelete();
        TransferShipHeaderDelete();
        TransferReceiptHeaderDelete();
    end;

For G/L Entry Table records deletion –

procedure GLEntryDelete()
    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        GLEntry.Reset();
        GLEntry.SetFilter("Posting Date", '<%1', deletiondate);
        GLEntry.DeleteAll(true);
    end;

For Deletion of records of Posted G/L entry table.

procedure PostedGLEntryDelete()
    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        PostedGLEntry.Reset();
        PostedGLEntry.SetFilter("Posting Date", '<%1', deletiondate);
        PostedGLEntry.DeleteAll(true);
    end

For deletion of Posted Sales Invoices table records.

procedure SalesInvoiceLineHeaderDelete()
    var
        PostSalesDelete: Codeunit "PostSales-Delete";

    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        salesInvHeader.Reset();
        SalesInvLine.Reset();
        SalesCommentLine.Reset();
        PostedDeferralHeader.Reset();
        salesInvHeader.SetFilter("Posting Date", '<%1', deletiondate);
        if salesInvHeader.FindSet() then begin
            repeat
                PostSalesDelete.DeleteSalesInvLines(salesInvHeader);
                SalesCommentLine.Reset();
                SalesCommentLine.SetRange("Document Type", SalesCommentLine."Document Type"::"Posted Invoice");
                SalesCommentLine.SetRange("No.", salesInvHeader."No.");
                SalesCommentLine.DeleteAll();
                ApprovalsMgmt.DeletePostedApprovalEntries(salesInvHeader.RecordId);
                PostedDeferralHeader.DeleteForDoc(
                    Enum::"Deferral Document Type"::Sales.AsInteger(), '', '',
                    SalesCommentLine."Document Type"::"Posted Invoice".AsInteger(), salesInvHeader."No.");
                salesInvHeader.Delete();
            until salesInvHeader.Next() = 0;
        end;
    end;

For deletion of Posted Sales Shipment table records.

procedure SalesShipLineHeaderDelete()
    var
        PostSalesDelete: Codeunit "PostSales-Delete";
        CertificateOfSupply: Record "Certificate of Supply";

    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        SalesShipHeader.Reset();
        SalesShipLine.Reset();
        SalesCommentLine.Reset();
        CertificateOfSupply.Reset();
        SalesShipHeader.SetFilter("Posting Date", '<%1', deletiondate);
        if SalesShipHeader.FindSet() then begin
            repeat
                SalesShipLine.SetRange("Document No.", SalesShipHeader."No.");
                if SalesShipLine.Find('-') then
                    repeat
                        SalesShipLine.Delete();
                    until SalesShipLine.Next() = 0;
                SalesCommentLine.SetRange("Document Type", SalesCommentLine."Document Type"::Shipment);
                SalesCommentLine.SetRange("No.", SalesShipHeader."No.");
                SalesCommentLine.DeleteAll();
                ApprovalsMgmt.DeletePostedApprovalEntries(SalesShipHeader.RecordId);
                if CertificateOfSupply.Get(CertificateOfSupply."Document Type"::"Sales Shipment", SalesShipHeader."No.") then
                    CertificateOfSupply.Delete(true);
                SalesShipHeader.Delete();
            until SalesShipHeader.Next() = 0;
        end;
    end;

For deletion of Posted Purchase Invoice table records.

procedure PurchaseInvoiceLineHeaderDelete()
    var
        PostPurchDelete: Codeunit "PostPurch-Delete";

    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        PurchaseInvHeader.Reset();
        PurchaseInvLine.Reset();
        PurchCommentLine.Reset();
        PostedDeferralHeader.Reset();
        PurchaseInvHeader.SetFilter("Posting Date", '<%1', deletiondate);
        if PurchaseInvHeader.FindSet() then begin
            repeat
                PostPurchDelete.DeletePurchInvLines(PurchaseInvHeader);
                PurchCommentLine.SetRange("Document Type", PurchCommentLine."Document Type"::"Posted Invoice");
                PurchCommentLine.SetRange("No.", PurchaseInvHeader."No.");
                PurchCommentLine.DeleteAll();
                ApprovalsMgmt.DeletePostedApprovalEntries(PurchaseInvHeader.RecordId);
                PostedDeferralHeader.DeleteForDoc(
                    Enum::"Deferral Document Type"::Purchase.AsInteger(), '', '',
                    PurchCommentLine."Document Type"::"Posted Invoice".AsInteger(), PurchaseInvHeader."No.");
                PurchaseInvHeader.Delete();
            until PurchaseInvHeader.Next() = 0;
        end;
    end;

For deletion of Posted Purchase Receipt table records.

procedure PurchaseReceiptDelete()
    var
        PostPurchDelete: Codeunit "PostPurch-Delete";
    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        PurchRcptHeader.Reset();
        PurchRcptLine.Reset();
        PurchCommentLine.Reset();
        PurchRcptHeader.SetFilter("Posting Date", '<%1', deletiondate);
        if PurchRcptHeader.FindSet() then begin
            repeat
                PurchRcptLine.SetRange("Document No.", PurchRcptHeader."No.");
                if PurchRcptLine.Find('-') then
                    repeat
                        PurchRcptLine.Delete();
                    until PurchRcptLine.Next() = 0;
                PurchCommentLine.SetRange("Document Type", PurchCommentLine."Document Type"::Receipt);
                PurchCommentLine.SetRange("No.", PurchRcptHeader."No.");
                PurchCommentLine.DeleteAll();
                ApprovalsMgmt.DeletePostedApprovalEntries(PurchRcptHeader.RecordId);
                PurchRcptHeader.Delete();
            until PurchRcptHeader.Next() = 0;
        end;
    end;

For deletion of Posted Transfer Shipment table records –

procedure TransferShipHeaderDelete()
    var
    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        TransferShipHeader.Reset();
        InvtCommentLine.Reset();
        TransShptLine.Reset();
        TransferShipHeader.SetFilter("Posting Date", '<%1', deletiondate);
        if TransferShipHeader.FindSet() then begin
            repeat
                TransShptLine.SetRange("Document No.", TransferShipHeader."No.");
                if TransShptLine.Find('-') then
                    repeat
                        TransShptLine.Delete();
                    until TransShptLine.Next() = 0;
                InvtCommentLine.SetRange("Document Type", InvtCommentLine."Document Type"::"Posted Transfer Shipment");
                InvtCommentLine.SetRange("No.", TransferShipHeader."No.");
                InvtCommentLine.DeleteAll();
                ItemTrackingMgt.DeleteItemEntryRelation(
                  DATABASE::"Transfer Shipment Line", 0, TransferShipHeader."No.", '', 0, 0, true);
                MoveEntries.MoveDocRelatedEntries(DATABASE::"Transfer Shipment Header", TransferShipHeader."No.");
                TransferShipHeader.Delete();
            until TransferShipHeader.Next() = 0;
        end;
    end;

For deletion of posted transfer receipt table records.

procedure TransferReceiptHeaderDelete()
    begin
        if ERPSetup.Get() then
            deletiondate := ERPSetup."Deletion Date";
        TransferReceiptHeader.Reset();
        InvtCommentLine.Reset();
        TransRcptLine.Reset();
        TransferReceiptHeader.SetFilter("Posting Date", '<%1', deletiondate);
        if TransferReceiptHeader.FindSet() then begin
            repeat
                TransRcptLine.SetRange("Document No.", TransferReceiptHeader."No.");
                if TransRcptLine.Find('-') then
                    repeat
                        TransRcptLine.Delete(true);
                    until TransRcptLine.Next() = 0;
                InvtCommentLine.SetRange("Document Type", InvtCommentLine."Document Type"::"Posted Transfer Receipt");
                InvtCommentLine.SetRange("No.", TransferReceiptHeader."No.");
                InvtCommentLine.DeleteAll();
                ItemTrackingMgt.DeleteItemEntryRelation(
                  DATABASE::"Transfer Receipt Line", 0, TransferReceiptHeader."No.", '', 0, 0, true);
                MoveEntries.MoveDocRelatedEntries(DATABASE::"Transfer Receipt Header", TransferReceiptHeader."No.");
                TransferReceiptHeader.Delete();
            until TransferReceiptHeader.Next() = 0;
        end;
    end;

Global variable used in all above code –

var
        SalesInvLine: Record "Sales Invoice Line";
        salesInvHeader: Record "Sales Invoice Header";
        SalesCommentLine: Record "Sales Comment Line";
        ApprovalsMgmt: Codeunit "Approvals Mgmt.";
        PostedDeferralHeader: Record "Posted Deferral Header";
        GLEntry: Record "G/L Entry";
        PostedGLEntry: Record "Posted Gen. Journal Line";
        SalesShipLine: Record "Sales Shipment Line";
        SalesShipHeader: Record "Sales Shipment Header";
        PurchaseInvLine: Record "Purch. Inv. Line";
        PurchaseInvHeader: Record "Purch. Inv. Header";
        PurchCommentLine: Record "Purch. Comment Line";
        PurchRcptLine: Record "Purch. Rcpt. Line";
        PurchRcptHeader: Record "Purch. Rcpt. Header";
        TransferShipHeader: Record "Transfer Shipment Header";
        TransShptLine: Record "Transfer Shipment Line";
        InvtCommentLine: Record "Inventory Comment Line";
        TransferReceiptHeader: Record "Transfer Receipt Header";
        ItemTrackingMgt: Codeunit "Item Tracking Management";
        TransRcptLine: Record "Transfer Receipt Line";
        MoveEntries: Codeunit MoveEntries;
        ERPSetup: Record "Setup Table";
        deletiondate: Date;

If you want to read next blog “How to Allow Posted Document Modification in Microsoft Dynamics 365 Business Central” then click the link below:

link: https://bizcentralorbit.com/how-to-allow-posted-document-modification-in-microsoft-dynamics-365-business-central/

If you want a Tutorial videos of “Customer Card – Business Central” then click the link below:

link: https://www.youtube.com/watch?v=SEls0uKWsdk&list=PLh-SKFWO2XjLyj_s55NfeKP_XBoQ1hWR7

Raise a support ticket instantly by clicking the link below:

https://bizcentralorbit.com/contact-us/

Leave a Comment

Your email address will not be published. Required fields are marked *

0
    0
    Your Cart
    Your cart is empty
    Scroll to Top