web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Answered

Code to revert the Finalize action on the Purchase orders

(1) ShareShare
ReportReport
Posted on by 352
Hello,
There are some bunch of Purchase Orders that are accidentally finalized by a user. I know there is no option from the UI to undo this. I am trying to write a x++ job to revert the status and worried on the risks associated with it. Can anyone suggest me on what tables are affected and should be considered in the job. 
 
Thanks
I have the same question (0)
  • Verified answer
    Anton Venter Profile Picture
    20,221 Super User 2025 Season 2 on at
    Code to revert the Finalize action on the Purchase orders
    You have to be really careful with update scripts in the production environment. A small mistake can have severe consequences making the problem worse.  You are trying to help a user, and if a mistake is made, you will become the owner of this problem and will have the responsibility to fix it. You might already know this but I am writing this for future readers of this post :-). The script provided below will update all purchases orders and purchase order lines that are finalized.
     
    Having said that, give us more information about what happened and why it was decided to fix it with a script. How many purchase orders have been finalized by this user? Is it not a possibility to create new purchase orders? If not, why is that? What is the  status of the purchased inventory of the purchase orders (if relevant)?
  • Suggested answer
    Saif Ali Sabri Profile Picture
    2,346 Super User 2025 Season 2 on at
    Code to revert the Finalize action on the Purchase orders

    In Dynamics 365 Finance and Operations, finalizing a Purchase Order (PO) is a significant action that prevents further editing and processing of the PO. Reverting the status of finalized POs requires a custom X++ script to update the related tables because there is no out-of-the-box feature to undo the "Finalize" action. However, modifying finalized POs directly through X++ is risky and should be carefully planned, tested, and validated.

    Below is a step-by-step guide on how to write the X++ code to revert the "Finalize" action, as well as an overview of the tables and risks to consider.


    Key Considerations and Risks

    1. Understand the Finalize Action:

      • When a Purchase Order is finalized, the system updates the PurchTable and related PurchLine records to a state that prevents further changes. Specifically:
        • PurchTable: The DocumentStatus is set to Finalized.
        • PurchLine: Similarly, the DocumentStatus is set to Finalized.
    2. Impact of Reverting the Finalize Action:

      • Reverting the DocumentStatus in PurchTable and PurchLine allows the PO to be editable again. However:
        • If the PO has been posted (e.g., a Product Receipt or Invoice), reverting the status could lead to data integrity issues.
        • Other dependent tables (such as workflows, approval logs, or journal postings) may have states or references tied to the PO's finalized state.
    3. Testing Environment:

      • Always test the script in a sandbox environment before running it in production.
      • Take a backup of the affected data before making changes.
    4. Identify Affected POs:

      • Make sure you know which POs need to be reverted (e.g., by filtering on DocumentStatus = Finalized in the PurchTable).

    Primary Tables to Consider

    1. PurchTable:
      • Main table for Purchase Orders.
      • Relevant field: DocumentStatus.
    2. PurchLine:
      • Contains the PO lines.
      • Relevant field: DocumentStatus.

    X++ Job to Revert the Finalize Action

    Here’s an example X++ script to revert the finalized status on the Purchase Orders:

    x++
    static void RevertFinalizedPurchaseOrders(Args _args)
    {
    PurchTable purchTable;
    PurchLine purchLine;
    ttsBegin;

    // Filter for finalized Purchase Orders
    while select forUpdate purchTable
    where purchTable.DocumentStatus == DocumentStatus::Finalized
    {
    // Log the PO for auditing (optional)
    info(strFmt("Reverting status for PO: %1", purchTable.PurchId));

    // Revert the status on PurchTable
    purchTable.DocumentStatus = DocumentStatus::InReview; // Change to desired status
    purchTable.update();

    // Update related PurchLine records
    while select forUpdate purchLine
    where purchLine.PurchId == purchTable.PurchId
    {
    purchLine.DocumentStatus = DocumentStatus::InReview; // Change to desired status
    purchLine.update();
    }
    }

    ttsCommit;

    info("Finalize action reverted for selected Purchase Orders.");
    }

    Explanation of the Code

    1. Filtering the Purchase Orders:

      • The PurchTable is filtered for DocumentStatus::Finalized. Modify this filter if needed (e.g., limit the query to specific POs or vendors).
    2. Reverting PurchTable.DocumentStatus:

      • The DocumentStatus field on PurchTable is updated from Finalized to another valid status (e.g., InReview or Approved).
    3. Reverting PurchLine.DocumentStatus:

      • For each PurchTable record, the corresponding PurchLine records are updated to reflect the same status change.
    4. Transaction Management:

      • The code uses a ttsBegin/ttsCommit block to ensure atomicity. If an error occurs, the changes will roll back.

    Custom Validation

    Before reverting the status, add validation checks to avoid data integrity issues. For example:

    • Skip Posted POs: Ensure that finalized POs with posted Product Receipt or Invoice are not reverted.
    x++
    if (purchTable.ReceiptStatus != ReceiptStatus::None || purchTable.InvoiceStatus != InvoiceStatus::None)
    {
    warning(strFmt("PO %1 has product receipts or invoices posted. Skipping.", purchTable.PurchId));
    continue;
    }
    • Limit Changes to a Specific Range of POs:
      • Use additional filters (e.g., CreatedDateTime or VendorAccount) to narrow down the selection of POs for reverting.

    Testing the Script

    1. Backup the Data:
      • Take a database backup of your test environment.
    2. Test on a Subset:
      • Run the script on a small set of test data before scaling it up to larger volumes.
    3. Validate the Results:
      • After running the script, verify:
        • The status of PurchTable and PurchLine records has reverted correctly.
        • The POs can now be edited as expected.
        • There are no unintended side effects (e.g., issues with workflows or linked documents).

    Risk Mitigation

    To minimize risks:

    1. Audit Trail:

      • Maintain a log of all reverted POs for audit purposes (e.g., write a record to a custom table or export the list to a file).
    2. Dependencies:

      • Identify other dependencies, such as:
        • Workflow status (WorkflowTrackingTable).
        • Related journals or ledger postings.
      • Manually verify these dependencies before proceeding.
    3. Production Deployment:

      • Perform the action during a low-usage period (e.g., outside business hours) to reduce system impact.

    Summary

    1. Tables to Update:

      • PurchTable → Update DocumentStatus.
      • PurchLine → Update DocumentStatus.
    2. Key Fields:

      • DocumentStatus (set to a valid status such as InReview or Approved).
    3. Risks:

      • Ensure POs with posted Product Receipts or Invoices are excluded.
      • Validate all dependent records and processes before reverting.
    4. Testing:

      • Test in a sandbox environment first and validate the results thoroughly.

    This approach will safely revert the "Finalize" action while minimizing risks.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Andrés Arias – Community Spotlight

We are honored to recognize Andrés Arias as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Sohaib Cheema Profile Picture

Sohaib Cheema 789 User Group Leader

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 607 Super User 2025 Season 2

#3
Martin Dráb Profile Picture

Martin Dráb 497 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans