Back to InsightsD365 F&O

How to Cancel a Purchase Order Using X++ Code

Apr 24, 2025 5 min read D365 F&O

Most organizations need batch jobs in which they want to cancel a purchase order when a particular business event occurs. For this, the Technical Consultant can use the following X++ code:

xpp
internal final class PurchaseOrderCancel
{
    /// <summary>
    /// Class entry point. This runnable class is designed to cancel a purchase order using X++ code.
    /// </summary>
    /// <param name="_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        PurchTable purchTable = PurchTable::find("PO-123"); // Enter your purchase order ID here
        PurchLine purchLine;

        ttsbegin;

        while select forupdate * from purchLine
            where purchLine.PurchId == purchTable.PurchId
               && purchLine.IsDeleted == NoYes::No
        {
            if (purchLine)
            {
                // Set remaining inventory quantity to zero
                purchLine.RemainInventPhysical = 0;

                // Set remaining physical quantity to zero
                purchLine.RemainPurchPhysical = 0;

                // Cancel the purchase line
                purchLine.PurchStatus = PurchStatus::Canceled;

                // Update PurchLine
                purchLine.update();

                // This method will update the inventory transactions
                InventMovement::bufferSetRemainQty(purchLine);
            }
        }

        ttscommit;
    }
}

How It Works

  1. Find the Purchase Order: The `PurchTable::find("PO-123")` method retrieves the purchase order by its ID. Replace `"PO-123"` with your actual PO number.
  1. Loop Through Purchase Lines: The `while select` loop iterates over all non-deleted purchase lines associated with the purchase order.
  1. Zero Out Quantities: Setting `RemainInventPhysical` and `RemainPurchPhysical` to `0` ensures no remaining quantity is expected from the vendor.
  1. Set Status to Canceled: `PurchStatus::Canceled` marks the line as cancelled, mirroring what D365 does through the UI.
  1. Update Inventory Transactions: `InventMovement::bufferSetRemainQty(purchLine)` ensures inventory transactions are updated consistently with the cancellation.

Important Notes

  • Always wrap purchase order updates in a ttsbegin/ttscommit transaction to ensure data integrity.
  • Test this code in a sandbox environment before running it in production.
  • Ensure the PO is in a state that allows cancellation (e.g., not fully invoiced or received).
  • For bulk cancellations in a batch job, wrap this logic in a `BatchHeader` class for proper batch processing support.

Have a Dynamics 365 Challenge?

Our experts are ready to help. Book a free consultation today.

Talk to an Expert