Skip to main content
Question

Automatically Trigger Release Button Logic in Move Screen from Materials Screen


Forum|alt.badge.img+2

I am currently writing logic to automatically create move transaction records from the materials screen. Currently the records are being created successfully via code but when I try to release the move transaction automatically I get the following error: “Parent Lot/ Serial Number is required.”

But on creating the move transaction automatically the parent lot/ serial number is being correctly assigned as below:

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.Objects.Common;
using PX.Objects.Common.Exceptions;
using PX.Objects.IN;
using PX.Objects.CM;
using PX.Objects.CS;
using PX.Objects.AM.Attributes;
using PX.Objects.PM;
using PX.Objects.GL;
using PX.Objects;
using PX.Objects.AM;


namespace PX.Objects.AM
{
  public class MaterialEntry_Extension : PXGraphExtension<PX.Objects.AM.MaterialEntry>
  {

        #region Release Override            
  public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
    // First, execute the base release method to ensure original functionality
            var documents = baseMethod(adapter).Cast<AMBatch>().ToList();

            // Process move transactions after base release
            foreach (AMBatch batch in documents)
            {
                CreateMoveTransactions(batch);
            }
            return documents;
}
#endregion
 private void CreateMoveTransactions(AMBatch batch)
{
    try
    {
        PXTrace.WriteInformation($"Starting CreateMoveTransactions for source batch: {batch.BatNbr}");

        var moveGraph = PXGraph.CreateInstance<MoveEntry>();
        PXTrace.WriteInformation($"Created new MoveEntry graph instance");

        // Create and insert the move batch
        PXTrace.WriteInformation($"Creating new move batch with TranDate: {batch.TranDate}, FinPeriodID: {batch.FinPeriodID}");
        var moveBatch = moveGraph.batch.Insert(new AMBatch
        {
            TranDate = batch.TranDate,
            FinPeriodID = batch.FinPeriodID,
            Hold = false
        });

        if (moveBatch == null)
        {
            PXTrace.WriteError("Failed to insert move batch - batch is null");
            throw new PXException("Failed to create move batch.");
        }

        PXTrace.WriteInformation($"Created move batch: {moveBatch.BatNbr}, DocType: {moveBatch.DocType}");

        // Set current batch
        moveGraph.batch.Current = moveBatch;
        PXTrace.WriteInformation($"Set current batch to: {moveBatch.BatNbr}");

        // Copy transactions from original batch
        int transactionCount = 0;
        var materialTrans = PXSelect<AMMTran,
            Where<AMMTran.batNbr, Equal<Required<AMMTran.batNbr>>,
            And<AMMTran.docType, Equal<Required<AMMTran.docType>>>>>
            .Select(moveGraph, batch.BatNbr, batch.DocType);

        PXTrace.WriteInformation($"Found {materialTrans.Count} source transactions to copy");

        foreach (AMMTran mtran in materialTrans)
        {
            transactionCount++;
            PXTrace.WriteInformation($"Processing transaction #{transactionCount}: LineNbr={mtran.LineNbr}, InventoryID={mtran.InventoryID}, LotSerialNbr={mtran.LotSerialNbr}");

            var parentLotSerial = string.IsNullOrEmpty(mtran.ParentLotSerialNbr)
                ? mtran.LotSerialNbr
                : mtran.ParentLotSerialNbr;

            PXTrace.WriteInformation($"Setting ParentLotSerialNbr to: {parentLotSerial}");

            var moveTran = new AMMTran
            {
                OrderType = mtran.OrderType,
                ProdOrdID = mtran.ProdOrdID,
                OperationID = mtran.OperationID,
                SiteID = mtran.SiteID,
                LocationID = mtran.LocationID,
                LotSerialNbr = mtran.LotSerialNbr,
                ParentLotSerialNbr = parentLotSerial,
                Qty = 1m
            };

            PXTrace.WriteInformation($"Creating move transaction for ProdOrdID: {moveTran.ProdOrdID}, OperationID: {moveTran.OperationID}");
            moveGraph.transactions.Insert(moveTran);
            PXTrace.WriteInformation($"Successfully inserted move transaction");
        }

        PXTrace.WriteInformation($"Finished processing {transactionCount} transactions");

        // Save transactions
        PXTrace.WriteInformation("Saving all move transactions...");
        moveGraph.Actions.PressSave();
        PXTrace.WriteInformation($"Successfully saved {transactionCount} transactions in batch {moveBatch.BatNbr}");

        // SIMPLE RELEASE - Just press the release button
        PXTrace.WriteInformation($"Attempting to release move batch {moveBatch.BatNbr}...");
        moveGraph.release.Press();
        PXTrace.WriteInformation($"Successfully released move batch {moveBatch.BatNbr}");
    }
    catch (Exception ex)
    {
        PXTrace.WriteError($"Error in CreateMoveTransactions: {ex.ToString()}");
        throw;
    }
}                 

        #endregion          
  }
}

Please let me know what I might be missing, thank you!

3 replies

davidnavasardyan
Jr Varsity I
Forum|alt.badge.img+3

Hi ​@TharidhiP 

When you insert a record via code, fields like ParentLotSerialNbr often depend on more than just setting the value directly — Acumatica sometimes needs to run field events or use cache setters to fully validate them.

Try explicitly setting both via Cache.SetValueExt or triggering the proper field events:

var moveTran = new AMMTran();
moveTran.OrderType = mtran.OrderType;
moveTran.ProdOrdID = mtran.ProdOrdID;
moveTran.OperationID = mtran.OperationID;
moveTran.SiteID = mtran.SiteID;
moveTran.LocationID = mtran.LocationID;

moveGraph.transactions.Insert(moveTran);

moveGraph.transactions.SetValueExt<AMMTran.lotSerialNbr>(moveTran, mtran.LotSerialNbr);
moveGraph.transactions.SetValueExt<AMMTran.parentLotSerialNbr>(moveTran, parentLotSerial);

moveGraph.transactions.SetValueExt<AMMTran.qty>(moveTran, 1m);

This ensures that the DAC-level validations and business logic are fired — sometimes just assigning properties directly on a new object skips that critical logic.


Forum|alt.badge.img+2
  • Author
  • Pro I
  • 105 replies
  • April 17, 2025

Hi ​@davidnavasardyan thank you for the suggestion! I have tried this and now get the following exception. I think doing the release action for the move screen inside the release override for the materials screen creates concurrency issues. 

PX.Data.PXLockViolationException 2025-04-16 23:29:22 UTCError: Another process has updated the 'AMProdItem' record. Your changes will be lost.
 PX.Data.PXOperationCompletedSingleErrorException 2025-04-16 23:29:22 UTCError: Another process has updated the 'AMProdItem' record. Your changes will be lost.
Error 2025-04-16 23:29:22 UTCThe transactions related to the Move batch 008176 cannot be released: Error: Another process has updated the 'AMProdItem' record. Your changes will be lost..
PX.Data.PXOperationCompletedSingleErrorException 2025-04-16 23:29:22 UTCError: Another process has updated the 'AMProdItem' record. Your changes will be lost.
Error 2025-04-16 23:29:22 UTCError: Another process has updated the 'AMProdItem' record. Your changes will be lost.

private void CreateMoveTransactions(AMBatch batch)
{
    try
    {
        PXTrace.WriteInformation($"Starting CreateMoveTransactions for source batch: {batch.BatNbr}");

        var moveGraph = PXGraph.CreateInstance<MoveEntry>();
        PXTrace.WriteInformation($"Created new MoveEntry graph instance");

        // Create and insert the move batch
        PXTrace.WriteInformation($"Creating new move batch with TranDate: {batch.TranDate}, FinPeriodID: {batch.FinPeriodID}");
        var moveBatch = moveGraph.batch.Insert(new AMBatch
        {
            TranDate = batch.TranDate,
            FinPeriodID = batch.FinPeriodID,
            Hold = false
        });

        if (moveBatch == null)
        {
            PXTrace.WriteError("Failed to insert move batch - batch is null");
            throw new PXException("Failed to create move batch.");
        }

        PXTrace.WriteInformation($"Created move batch: {moveBatch.BatNbr}, DocType: {moveBatch.DocType}");

        // Set current batch
        moveGraph.batch.Current = moveBatch;
        PXTrace.WriteInformation($"Set current batch to: {moveBatch.BatNbr}");

        // Copy transactions from original batch
        int transactionCount = 0;
        var materialTrans = PXSelect<AMMTran,
            Where<AMMTran.batNbr, Equal<Required<AMMTran.batNbr>>,
            And<AMMTran.docType, Equal<Required<AMMTran.docType>>>>>
            .Select(moveGraph, batch.BatNbr, batch.DocType);

        PXTrace.WriteInformation($"Found {materialTrans.Count} source transactions to copy");

        foreach (AMMTran mtran in materialTrans)
        {
            transactionCount++;
            PXTrace.WriteInformation($"Processing transaction #{transactionCount}: LineNbr={mtran.LineNbr}, InventoryID={mtran.InventoryID}, LotSerialNbr={mtran.LotSerialNbr}");

            var parentLotSerial = string.IsNullOrEmpty(mtran.ParentLotSerialNbr)
                ? mtran.LotSerialNbr
                : mtran.ParentLotSerialNbr;

            PXTrace.WriteInformation($"Setting ParentLotSerialNbr to: {parentLotSerial}");

            // Create empty move transaction and insert it first
            var moveTran = new AMMTran();
            moveTran.OrderType = mtran.OrderType;
            moveTran.ProdOrdID = mtran.ProdOrdID;
            moveTran.OperationID = mtran.OperationID;
            moveTran.SiteID = mtran.SiteID;
            moveTran.LocationID = mtran.LocationID;

            PXTrace.WriteInformation($"Creating move transaction for ProdOrdID: {moveTran.ProdOrdID}, OperationID: {moveTran.OperationID}");
            var insertedTran = moveGraph.transactions.Insert(moveTran);

            if (insertedTran != null)
            {
                // Set fields using SetValueExt to trigger field events and validations
                moveGraph.transactions.SetValueExt<AMMTran.lotSerialNbr>(insertedTran, mtran.LotSerialNbr);
                moveGraph.transactions.SetValueExt<AMMTran.parentLotSerialNbr>(insertedTran, parentLotSerial);
                moveGraph.transactions.SetValueExt<AMMTran.qty>(insertedTran, 1m);

                // Update after setting values
                moveGraph.transactions.Update(insertedTran);
                PXTrace.WriteInformation($"Successfully inserted and updated move transaction with ParentLotSerialNbr: {parentLotSerial}");
            }
            else
            {
                PXTrace.WriteError($"Failed to insert move transaction for line {mtran.LineNbr}");
            }
        }

        PXTrace.WriteInformation($"Finished processing {transactionCount} transactions");

        // Save transactions
        PXTrace.WriteInformation("Saving all move transactions...");
        moveGraph.Actions.PressSave();
        PXTrace.WriteInformation($"Successfully saved {transactionCount} transactions in batch {moveBatch.BatNbr}");

        // SIMPLE RELEASE - Just press the release button
        PXTrace.WriteInformation($"Attempting to release move batch {moveBatch.BatNbr}...");
        moveGraph.release.Press();
        PXTrace.WriteInformation($"Successfully released move batch {moveBatch.BatNbr}");
    }
    catch (Exception ex)
    {
        PXTrace.WriteError($"Error in CreateMoveTransactions: {ex.ToString()}");
        throw;
    }
}

 

How can I amend this?

Thank you!


davidnavasardyan
Jr Varsity I
Forum|alt.badge.img+3

@TharidhiP 

Here is a great article on how to prevent the well-known PXLockViolationException

https://blog.zaletskyy.com/post/2023/04/19/another-process-has-updated-the-record-your-changes-will-be-lost


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings