Automating Prepayment Handling in Business Central – Part 2 - CloudFronts

Automating Prepayment Handling in Business Central – Part 2

In Part 1, we explored the core logic of handling prepayment invoices in Business Central using AL. In this part, we will dive deeper into the practical implementation, focusing on how prepayments are applied, invoices are generated, and item charges are assigned. This blog will break down the logic in a simplified, yet complete way.

Why Automate Prepayments?

In real-world business scenarios, companies often pay vendors before the invoice is fully posted. Handling these prepayments manually is tedious and error-prone:

  • a. Matching payments with invoices can be cumbersome.
  • b. Multiple vendors in one purchase order complicate tracking.
  • c. Unapplying and reapplying payments manually is risky.

Our AL code automates this process: it creates purchase invoices, handles prepayment lines, applies payments, and ensures that item charges are correctly assigned.

1. Event Subscriber: Trigger After Posting Purchase Document

The automation starts with an event subscriber that triggers after a purchase document is posted:

[EventSubscriber(ObjectType::Codeunit, Codeunit::”Purch.-Post”, ‘OnAfterPostPurchaseDoc’, ”, false, false)]
procedure OnAfterPostPurchaseDocHandler(var PurchaseHeader: Record “Purchase Header”)
var
    Rec_PreppaymentLines: Record PrepaymentLinesandPayment;
    PurchInvoiceHeader: Record “Purchase Header”;
    VendorInvoiceMap: Dictionary of [Code[20], Code[20]];
    VendorNo: Code[20];
begin
    // Collect unique vendors
    Rec_PreppaymentLines.SetRange(“Purchase Order No.”, PurchaseHeader.”No.”);
    Clear(VendorList);
    if Rec_PreppaymentLines.FindSet() then
        repeat
            if not VendorList.Contains(Rec_PreppaymentLines.”Vendor No.”) then
                VendorList.Add(Rec_PreppaymentLines.”Vendor No.”);
        until Rec_PreppaymentLines.Next() = 0;

// Process each vendor
    foreach VendorNo in VendorList do begin
        // Create or reuse invoice
        if VendorInvoiceMap.ContainsKey(VendorNo) then
            PurchInvoiceHeader.Get(PurchInvoiceHeader.”Document Type”::Invoice, VendorInvoiceMap.Get(VendorNo))
        else begin
            PurchInvoiceHeader := CreatePurchaseInvoiceHeader(VendorNo);
            VendorInvoiceMap.Add(VendorNo, PurchInvoiceHeader.”No.”);
        end;

// Handle prepayment lines
        Rec_PreppaymentLines.SetRange(“Purchase Order No.”, PurchaseHeader.”No.”);
        Rec_PreppaymentLines.SetRange(“Vendor No.”, VendorNo);
        if Rec_PreppaymentLines.FindSet() then
            repeat
                HandlePrepaymentLine(Rec_PreppaymentLines, PurchInvoiceHeader);
            until Rec_PreppaymentLines.Next() = 0;
    end;
end;

Key Takeaways:

  • a. Collects unique vendors from prepayment lines.
  • b. Creates a new purchase invoice for each vendor if not already existing.
  • c. prepayment lines for each vendor automatically.

2. Handling Prepayment Lines

The HandlePrepaymentLine procedure ensures each prepayment is processed correctly:

procedure HandlePrepaymentLine(var PrepaymentLine: Record PrepaymentLinesandPayment; var PurchHeader: Record “Purchase Header”)
var
    PaymentEntryNo: Integer;
begin
    // Unapply previous payments if any
    PaymentEntryNo := UnapplyPaymentFromPrepayInvoice(PrepaymentLine.”Prepayment Invoice”);
    if PaymentEntryNo = 0 then
        Error(‘Failed to unapply Vendor Ledger Entry for Document No. %1’, PrepaymentLine.”Prepayment Invoice”);

// Create credit memo and invoice line
    CreateCreditMemoLine(PrepaymentLine, PrepaymentLine.”Prepayment Invoice”);
    CreatePurchaseInvoiceLine(PurchHeader, PrepaymentLine);

// Assign item charges and post
    AssignItemChargeToReceiptAndPost(PrepaymentLine, PurchHeader.”No.”, PrepaymentLine.”Purchase Order No.”);
end;

Highlights:

  • a. Automatically unapplies previous payments to avoid double application.
  • b. Creates credit memo lines and purchase invoice lines.
  • c. Assigns item charges from purchase receipts to invoices.

3. Applying Payments to Invoice

The ApplyPaymentToInvoice procedure ensures the invoice is linked with the correct prepayment:

procedure ApplyPaymentToInvoice(InvoiceNo: Code[20]; PaymentEntryNo: Integer)
var
    InvoiceEntry, VendLedEntry: Record “Vendor Ledger Entry”;
    ApplyPostedEntries: Codeunit “VendEntry-Apply Posted Entries”;
    ApplyUnapplyParameters: Record “Apply Unapply Parameters”;
begin
    InvoiceEntry.SetRange(“Document No.”, InvoiceNo);
    InvoiceEntry.SetRange(Open, true);
    if InvoiceEntry.FindFirst() then begin
        VendLedEntry.SetRange(“Entry No.”, PaymentEntryNo);
        if VendLedEntry.FindFirst() then begin
            InvoiceEntry.Validate(“Amount to Apply”, InvoiceEntry.”Remaining Amount”);
            VendLedEntry.Validate(“Amount to Apply”, -InvoiceEntry.”Remaining Amount”);

ApplyUnapplyParameters.”Document No.” := VendLedEntry.”Document No.”;
            ApplyPostedEntries.Apply(InvoiceEntry, ApplyUnapplyParameters);
        end;
    end;
end;

Benefits:

  • a. Handles partial and full payments automatically.
  • b. Ensures accurate ledger entries and reconciliation.

4. Assigning Item Charges

Item charges from receipts are automatically assigned to invoices:

procedure AssignItemChargeToReceiptAndPost(var PrepaymentLine: Record PrepaymentLinesandPayment; PurchInvoiceNo: Code[20]; PurchaseOrderNo: Code[20])
var
    PurchRcptLine: Record “Purch. Rcpt. Line”;
    ItemChargeAssign: Record “Item Charge Assignment (Purch)”;
begin
    PurchRcptLine.SetRange(“Order No.”, PrepaymentLine.”Purchase Order No.”);
    PurchRcptLine.SetFilter(Quantity, ‘>0’);
    PurchRcptLine.SetRange(“No.”, PrepaymentLine.”Item No.”);

if PurchRcptLine.FindSet() then
        repeat
            ItemChargeAssign.Init();
            ItemChargeAssign.”Document No.” := PurchInvoiceNo;
            ItemChargeAssign.”Applies-to Doc. No.” := PurchRcptLine.”Document No.”;
            ItemChargeAssign.”Item Charge No.” := PrepaymentLine.”Item Charge”;
            ItemChargeAssign.”Qty. to Assign” := 1;
            ItemChargeAssign.”Amount to Assign” := PrepaymentLine.Amount;
            ItemChargeAssign.Insert(true);
        until PurchRcptLine.Next() = 0;
end;

Outcome:

  • a. Automates linking item charges to the correct invoice lines.
  • b. Eliminates manual errors in item charge assignments.

To conclude, by implementing this automation:

  • a. Prepayment handling becomes fully automated.
  • b. Reduces manual errors in posting, payment application, and invoice creation.
  • c. Supports multiple vendors and complex purchase orders seamlessly.
  • d. Ensures auditability and correct ledger entries in Business Central.

This code can save significant time for finance teams while keeping processes accurate and transparent.

We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com


Share Story :

SEARCH BLOGS :

FOLLOW CLOUDFRONTS BLOG :


Secured By miniOrange