Skip to main content
Question

"The transaction cannot be created for Production Order RG PP000504 because the 1H4N7820 lot or serial number has not been preassigned." On Executing A Custom Action in Material Screen

  • May 6, 2025
  • 3 replies
  • 67 views

Forum|alt.badge.img+2

I am trying to create the move transaction (AM302000) automatically after releasing the material record when the custom button (Create Move Record) is clicked in the materials screen (AM300000).

This is the code I have attempted below it is now creating the move transaction successfully for records where Lot/Serial Number and Parent Lot/Serial Number are the same but gives the following error for records where Lot/Serial Number and Parent Lot/Serial Number are different.

The transaction cannot be created for Production Order RG PP000504 because the 1H4N7820 lot or serial number has not been preassigned.

Example Record to Be Created in Move Screen
Related Production Order
namespace PX.Objects.AM                                        
{
public class MaterialEntry_Extension : PXGraphExtension<PX.Objects.AM.MaterialEntry>
{
// New action button to create move record after material release
public PXAction<AMBatch> CreateMoveRecord;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Create Move Record", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
protected void createMoveRecord()
{
if (Base.batch.Current == null || Base.batch.Current.Status != "R") // R = Released
{
throw new PXException("Move records can only be created from released material transactions.");
}

AMBatch moveBatch = CreateMoveTransactionsFromBatch(Base.batch.Current);

if (moveBatch != null)
{
// Redirect to the Move Entry screen with the new batch
var moveGraph = PXGraph.CreateInstance<MoveEntry>();
moveGraph.batch.Current = moveGraph.batch.Search<AMBatch.batNbr>(moveBatch.BatNbr);


// Automatically release the move batch
//try
//{
// moveGraph.release.Press();
// }
// catch (Exception ex)
// {
// throw new PXException($"Move Batch {moveBatch.BatNbr} was created but failed to release: {ex.Message}", ex);
// }

//throw new PXRedirectRequiredException(moveGraph, "Move Batch " + moveBatch.BatNbr + " Created");
// Create redirect exception with WindowMode.New to open in a new tab
var redirectException = new PXRedirectRequiredException(moveGraph, "Move Batch " + moveBatch.BatNbr + " Created");
redirectException.Mode = PXBaseRedirectException.WindowMode.New;
throw redirectException;
}
}

[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXRestrictor(
typeof(Where<SubNotLessThanZero<AMProdItemSplit.qty,
Add<AMProdItemSplit.qtyComplete, AMProdItemSplit.qtyScrapped>>,
NotEqual<decimal0>>),
"Remaining Quantity is 0.")]
protected virtual void _(Events.CacheAttached<AMMTranSplit.parentLotSerialNbr> e)
{
}

[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXRestrictor(
typeof(Where<SubNotLessThanZero<AMProdItemSplit.qty,
Add<AMProdItemSplit.qtyComplete, AMProdItemSplit.qtyScrapped>>,
NotEqual<decimal0>>),
"Remaining Quantity is 0.")]
protected virtual void _(Events.CacheAttached<AMMTran.parentLotSerialNbr> e)
{
}

protected virtual void _(Events.RowSelected<AMMTran> e)
{
if (e.Row == null) return;

var row = (AMMTran)e.Row;
AMBatch batch = Base.batch.Current;

// Make LotSerialNbr required
PXUIFieldAttribute.SetRequired<AMMTran.lotSerialNbr>(Base.transactions.Cache, true);
PXUIFieldAttribute.SetRequired<AMMTran.parentLotSerialNbr>(Base.transactions.Cache, true);

// Enable both fields at the cache level first
Base.transactions.Cache.AllowUpdate = true;
PXUIFieldAttribute.SetEnabled(Base.transactions.Cache, null, true);

// Then enable specific fields
PXUIFieldAttribute.SetEnabled<AMMTran.lotSerialNbr>(Base.transactions.Cache, null, true);
PXUIFieldAttribute.SetEnabled<AMMTran.parentLotSerialNbr>(Base.transactions.Cache, null, true);

// Enable for the specific row
PXUIFieldAttribute.SetEnabled<AMMTran.lotSerialNbr>(Base.transactions.Cache, row, true);
PXUIFieldAttribute.SetEnabled<AMMTran.parentLotSerialNbr>(Base.transactions.Cache, row, true);

if (batch != null && !string.IsNullOrWhiteSpace(row.LotSerialNbr) &&
!string.IsNullOrWhiteSpace(row.ParentLotSerialNbr))
{
Base.batch.Cache.SetValue<AMBatch.hold>(batch, false);
Base.batch.Update(batch);
}

// Show/hide the Create Move Record button based on batch status
bool isReleased = batch != null && batch.Status == "R";
CreateMoveRecord.SetEnabled(isReleased);
}

#endregion

// Helper method to create move transactions from a material batch
private AMBatch CreateMoveTransactionsFromBatch(AMBatch sourceBatch)
{
try
{
PXTrace.WriteInformation($"Starting CreateMoveTransactionsFromBatch for source batch: {sourceBatch.BatNbr}");

var moveGraph = PXGraph.CreateInstance<MoveEntry>();

// Create new move batch
var moveBatch = moveGraph.batch.Insert(new AMBatch
{
TranDate = sourceBatch.TranDate,
FinPeriodID = sourceBatch.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}");
moveGraph.batch.Current = moveBatch;

// Get source transactions
var materialTrans = PXSelect<AMMTran,
Where<AMMTran.batNbr, Equal<Required<AMMTran.batNbr>>,
And<AMMTran.docType, Equal<Required<AMMTran.docType>>>>>
.Select(moveGraph, sourceBatch.BatNbr, sourceBatch.DocType);

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

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

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


// Create move transaction
var moveTran = new AMMTran
{
OrderType = mtran.OrderType,
ProdOrdID = mtran.ProdOrdID,
OperationID = mtran.OperationID,
SiteID = mtran.SiteID,
LocationID = mtran.LocationID,
//add UOM and inventory
//InventoryID = mtran.InventoryID,
//UOM = mtran.UOM
};

var insertedTran = moveGraph.transactions.Insert(moveTran);
if (insertedTran != null)
{
//moveGraph.transactions.SetValueExt<AMMTran.prodOrdID>(insertedTran, mtran.ProdOrdID);
moveGraph.transactions.SetValueExt<AMMTran.lotSerialNbr>(insertedTran, mtran.LotSerialNbr);
moveGraph.transactions.SetValueExt<AMMTran.parentLotSerialNbr>(insertedTran, parentLotSerial);
moveGraph.transactions.SetValueExt<AMMTran.qty>(insertedTran, 1m);
//moveGraph.transactions.SetValueExt<AMMTran.inventoryID>(insertedTran, mtran.InventoryID);
//moveGraph.transactions.SetValueExt<AMMTran.uOM>(insertedTran, mtran.UOM);
moveGraph.transactions.Update(insertedTran);
}
else
{
PXTrace.WriteError($"Failed to insert move transaction for line {mtran.LineNbr}");
}
}

// Save all changes
moveGraph.Actions.PressSave();
PXTrace.WriteInformation($"Saved {transactionCount} move transactions for batch {moveBatch.BatNbr}");

// Store the batch number for release
// string batchNbr = moveBatch.BatNbr;

// SIMPLEST RELEASE APPROACH:
// Create a fresh instance of MoveEntry and release by batch number
// var releaseGraph = PXGraph.CreateInstance<MoveEntry>();
// releaseGraph.batch.Current = releaseGraph.batch.Search<AMBatch.batNbr>(batchNbr);

// if (releaseGraph.batch.Current != null)
// {
// PXTrace.WriteInformation($"Releasing batch {batchNbr}");
// releaseGraph.release.Press();
//}



return moveBatch;
}
catch (Exception ex)
{
PXTrace.WriteError($"Error in CreateMoveTransactionsFromBatch: {ex}");
throw new PXException($"Error creating move transactions: {ex.Message}");
}
}
}
}

This is the detailed error log:

    
Error in CreateMoveTransactionsFromBatch: System.Exception: The transaction cannot be created for Production Order RG PP000504 because the 1H4N7820 lot or serial number has not been preassigned.
at PX.Objects.AM.MoveEntryBase`1.ValidateLotSerialInformation() in C:\build\code_repo\WebSites\Pure\PX.Objects.AM\AM\MoveEntryBase.cs:line 174
at PX.Objects.AM.MoveEntryBase`1.Persist() in C:\build\code_repo\WebSites\Pure\PX.Objects.AM\AM\MoveEntryBase.cs:line 119
at PX.Data.PXSave`1.<HandlerInternal>g__Persist|3_2() in C:\build\code_repo\NetTools\PX.Data\Descriptor\Action\CommonActions.cs:line 98
at PX.Data.PXSave`1.<HandlerInternal>d__3.MoveNext() in C:\build\code_repo\NetTools\PX.Data\Descriptor\Action\CommonActions.cs:line 81
at PX.Data.PXAction`1.<Press>d__38.MoveNext() in C:\build\code_repo\NetTools\PX.Data\Descriptor\Action\PXAction.cs:line 1301
at PX.Data.PXAction`1.<Press>d__38.MoveNext() in C:\build\code_repo\NetTools\PX.Data\Descriptor\Action\PXAction.cs:line 1235
at PX.Data.PXActionCollection.PressSave(PXAction caller) in C:\build\code_repo\NetTools\PX.Data\Graph\Collection.cs:line 1456
at PX.Objects.AM.MaterialEntry_Extension.CreateMoveTransactionsFromBatch(AMBatch sourceBatch)

 

3 replies

Forum|alt.badge.img+1
  • Jr Varsity II
  • May 6, 2025

hi ​@TharidhiP ,

Please verify that the lot/serial numbers being assigned have a completed quantity of 0. If the completed quantity is 1, we encounter an issue even when adding the production number to the Move Transaction screen,

Production order line details
adding move transaction manually 

Hope above helps!!


Forum|alt.badge.img+2
  • Author
  • Pro III
  • May 8, 2025

Hi ​@Rakshanda thank you for your suggestion! I have checked the complete qty and it was always set to 0 from the beginning. Any other idea why this error comes?

 


Chris Hackett
Community Manager
Forum|alt.badge.img
  • Acumatica Community Manager
  • July 3, 2025

Hi ​@Rakshanda were you able to find a solution? Thank you!