Skip to main content

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);
rPXOverride]
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!

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.


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!


@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