I am facing an issue with a customization on the Acumatica 2025 R2 Receive and Put Away screen and would appreciate your guidance.
Issue Description:
I have added a custom Action Button on the Receive and Put Away screen. When the button is clicked, a popup window opens that displays a list of active locations in a grid with selection checkboxes.
The expected behavior is that when I select multiple locations in the popup and confirm the action, all selected locations should be processed and set to inactive.
Actual Behavior:
When more than one location is selected, only the last selected location is being processed and inactivated. The previously selected locations are ignored.
Expected Behavior:
All selected locations in the popup grid should be processed together, and the inactive logic should apply to each selected record.
Custom Code Reference
Below is the relevant customization code used for the popup and action button:
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using PX.Common;
using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.BarcodeProcessing;
using PX.Objects.Common;
using PX.Objects.AP;
using PX.Objects.IN;
using PX.Objects.IN.WMS;
using PX.Objects.Extensions;
using PX.Objects.IN.Overrides.INDocumentRelease;
using PX.Objects.PO.Scopes;
using System.Threading;
//using WMSBase = WarehouseManagementSystem<ReceivePutAway, ReceivePutAway.Host>;
using PX.Objects.SO.WMS;
using System.Runtime.Remoting.Messaging;
using AllocateAdjacentLocation;
using PX.Objects.PO;
namespace PX.Objects.PO.WMS
{
public class ReceivePutAwayExt : ReceivePutAway.ScanExtension
{
public SelectFrom<AvailableLocationStatus>.View AdjLoc;
protected virtual IEnumerable adjLoc()
{
POReceipt doc = Base.Document.Current;
string ReceiptNbr = doc?.ReceiptNbr;
if (ReceiptNbr == null)
{
yield break;
}
POReceiptSplitToTransferSplitLink ObjPORecSplit =
PXSelect<
POReceiptSplitToTransferSplitLink,
Where<
POReceiptSplitToTransferSplitLink.receiptNbr,
Equal<Required<POReceiptSplitToTransferSplitLink.receiptNbr>>>>
.Select(Base, ReceiptNbr);
// If location not scanned yet → show all available locations
if (ObjPORecSplit == null)
{
yield break;
}
INTran objINTran =
PXSelect<
INTran,
Where<
INTran.refNbr,
Equal<Required<INTran.refNbr>>>>
.Select(Base, ObjPORecSplit.TransferRefNbr);
// Get ToLocation LocationCD
INLocation toLocation = PXSelect<
INLocation,
Where<INLocation.locationID,
Equal<Required<INLocation.locationID>>>>
.Select(Base,objINTran.ToLocationID);
if (toLocation == null)
yield break;
string toLocCD = toLocation.LocationCD;
if (string.IsNullOrEmpty(toLocCD))
yield break;
// Remove trailing underscores
string cleanLoc = toLocCD.TrimEnd('_');
// Split segments
string[] parts = cleanLoc.Split('-');
if (parts.Length == 0)
yield break;
string lastPart = parts[parts.Length - 1];
// Read number (ignore leading zeros)
if (!int.TryParse(lastPart, out int number))
yield break;
// Always use 2 digits for next locations
int digits = 2; // <<< FIXED HERE — Force 2-digit code
// Rebuild prefix
string prefix = cleanLoc.Substring(0, cleanLoc.Length - lastPart.Length);
int currentNo = int.Parse(lastPart);
if (string.IsNullOrEmpty(prefix))
yield break;
// Query ONLY AvailableLocationStatus
var result =
SelectFrom<AvailableLocationStatus>
.Where<AvailableLocationStatus.locationCD.StartsWith<@P.AsString>
.And<AvailableLocationStatus.siteID.IsEqual<@P.AsInt>>>
.AggregateTo<
GroupBy<AvailableLocationStatus.locationID>,
GroupBy<AvailableLocationStatus.locationCD>>
.View.Select(Base, prefix,objINTran.SiteID);
HashSet<int?> seenLocations = new HashSet<int?>();
foreach (AvailableLocationStatus als in result)
{
// new Way to split Lication
if (string.IsNullOrEmpty(als.LocationCD))
yield break;
// Remove trailing underscores
string cleanLocs = als.LocationCD.TrimEnd('_');
// Split segments
string[] partss = cleanLocs.Split('-');
if (partss.Length == 0)
yield break;
string lastParts = partss[partss.Length - 1];
int locNo = int.Parse(lastParts);
// ✅ Include only NEXT adjacent locations
if (locNo > currentNo)
{
yield return als;
}
}
}
public PXAction<ScanHeader> AdjLocations;
[PXButton(CommitChanges = true)]
// [PXUIField(DisplayName = "Adjacent Locations")]
[PXUIField(DisplayName = "Adjacent Locations", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
protected virtual IEnumerable adjLocations(PXAdapter adapter)
{
// You can define a constant or a localized string for the message
const string Caption = "Adjacent Locations";
// Use the Ask() method with the specific overload that accepts
// a message/title parameter.
if (AdjLoc.AskExt() == WebDialogResult.OK)
{
AdjLoc.Cache.IsDirty = false;
var filter = AdjLoc.Current;
if (filter == null)
{
return adapter.Get();
}
POReceipt doc = Base.Document.Current;
if (doc == null) return adapter.Get();
POReceiptSplitToTransferSplitLink ObjPORecSplit =
PXSelect< POReceiptSplitToTransferSplitLink,
Where< POReceiptSplitToTransferSplitLink.receiptNbr, Equal<Required<POReceiptSplitToTransferSplitLink.receiptNbr>>>>
.Select(Base, doc.ReceiptNbr);
// If location not scanned yet → show all available locations
if (ObjPORecSplit == null) return adapter.Get();
INTran objINTran =
PXSelect<INTran,
Where<INTran.refNbr,Equal<Required<INTran.refNbr>>>>
.Select(Base, ObjPORecSplit.TransferRefNbr);
ItemAllocatedLocationsMaint ItemAllocatedLocationsGraph = PXGraph.CreateInstance<ItemAllocatedLocationsMaint>();
INSiteMaint graph = PXGraph.CreateInstance<INSiteMaint>();
// Load warehouse once
INSite warehouse = PXSelect<INSite,
Where<INSite.siteID, Equal<Required<INSite.siteID>>>>
.Select(graph, objINTran.SiteID);
graph.site.Current = warehouse;
List<int?> selectedLocationIDs = new List<int?>();
// foreach (AvailableLocationStatus obj in AdjLoc.Cache.Cached.Cast<AvailableLocationStatus>())
// foreach (AvailableLocationStatus obj in AdjLoc.Cache.Cached.Cast<AvailableLocationStatus>())
// foreach (AvailableLocationStatus obj in AdjLoc.Cache.Updated)
foreach (AvailableLocationStatus obj in AdjLoc.Select())
// foreach (AvailableLocationStatus obj in AdjLoc.Cache.Inserted)
{
PXTrace.WriteInformation(
$"Selected={obj.Selected}"
);
PXTrace.WriteInformation(
$"LocationID={obj.LocationID}, LocationCD={obj.LocationCD}"
);
if (obj.Selected == true)
{
selectedLocationIDs.Add(obj.LocationID);
PXTrace.WriteInformation(
$"ALocationID={obj.LocationID}, ALocationCD={obj.LocationCD}"
);
INLocation nextloc = SelectFrom<INLocation>
.Where<INLocation.locationID.IsEqual<P.AsInt>
.And<INLocation.siteID.IsEqual<P.AsInt>>>
.View.Select(Base, obj.LocationID, obj.SiteID)
.TopFirst;
if (nextloc == null) return adapter.Get();
// Set current location in warehouse
graph.location.Current = nextloc;
// Deactivate
nextloc.Active = false;
graph.location.Update(nextloc);
}
}
if (selectedLocationIDs.Count== 0) return adapter.Get();
// Save only once
graph.Actions.PressSave();
int? firstAdjLocationID = null;
int? secondAdjLocationID = null;
int? thirdAdjLocationID = null;
if (selectedLocationIDs.Count >= 1)
firstAdjLocationID = selectedLocationIDs[0];
if (selectedLocationIDs.Count >= 2)
secondAdjLocationID = selectedLocationIDs[1];
if (selectedLocationIDs.Count >= 3)
thirdAdjLocationID = selectedLocationIDs[2];
// 4. Insert second split
ItemAllocatedLocations ObjItemAlloLoc = new ItemAllocatedLocations();
// ObjItemAlloLoc.TranRefNbr=row.RefNbr;
ObjItemAlloLoc.InventoryID=objINTran.InventoryID;
ObjItemAlloLoc.SiteID=objINTran.SiteID;
ObjItemAlloLoc.ToLocationID=objINTran.ToLocationID;
ObjItemAlloLoc.FirstAdjLocationID = firstAdjLocationID;
ObjItemAlloLoc.SecondAdjLocationID = secondAdjLocationID;
ObjItemAlloLoc.ThirdAdjLocationID = thirdAdjLocationID;
ItemAllocatedLocationsGraph.IALView.Insert(ObjItemAlloLoc);
ItemAllocatedLocationsGraph.Actions.PressSave();
// AdjLoc.View.RequestRefresh();
}
return adapter.Get();
}
}
}
DAC Code
using System;
using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
namespace AllocateAdjacentLocation
{
[Serializable]
[PXCacheName("AvailableLocationStatus")]
public class AvailableLocationStatus : PXBqlTable, IBqlTable
{
#region Selected
[PXBool]
// [PXDefault(false)]
[PXUIField(DisplayName="Select")]
public virtual bool? Selected { get; set; }
public abstract class selected : PX.Data.BQL.BqlBool.Field<selected> { }
#endregion
#region RecordID
[PXDBInt()]
[PXUIField(DisplayName = "Record ID")]
public virtual int? RecordID { get; set; }
public abstract class recordID : PX.Data.BQL.BqlInt.Field<recordID> { }
#endregion
#region SiteID
[PXDBInt()]
[PXUIField(DisplayName = "Site ID")]
public virtual int? SiteID { get; set; }
public abstract class siteID : PX.Data.BQL.BqlInt.Field<siteID> { }
#endregion
#region LocationID
[PXDBInt()]
[PXUIField(DisplayName = "Location ID")]
public virtual int? LocationID { get; set; }
public abstract class locationID : PX.Data.BQL.BqlInt.Field<locationID> { }
#endregion
#region LocationCD
[PXDBString(30, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Location CD")]
public virtual string LocationCD { get; set; }
public abstract class locationCD : PX.Data.BQL.BqlString.Field<locationCD> { }
#endregion
#region Active
[PXDBBool()]
[PXUIField(DisplayName = "Active")]
public virtual bool? Active { get; set; }
public abstract class active : PX.Data.BQL.BqlBool.Field<active> { }
#endregion
}
}
Aspx Code Popup code
<px:PXSmartPanel runat="server" ID="CstSmartPanel1" Height="500px" Width="500px" LoadOnDemand="True" ShowAfterLoad="True" Caption="Adjacent Locations" Key="AdjLoc">
<px:PXGrid runat="server" ID="CstPXGrid1" Height="300px" Width="100%" DataSourceID="ds" SkinID="Details" AllowFilter="">
<Levels>
<px:PXGridLevel DataMember="AdjLoc">
<Columns>
<px:PXGridColumn DataField="Selected" Width="60" Type="CheckBox" CommitChanges="True" />
<px:PXGridColumn DataField="LocationCD" Width="140" />
<px:PXGridColumn DataField="LocationID" Width="70" /></Columns></px:PXGridLevel></Levels></px:PXGrid>
<px:PXPanel runat="server" ID="CstPanel2">
<px:PXButton runat="server" ID="CstButton3" Text="SAVE" DialogResult="OK" />
<px:PXButton runat="server" ID="CstButton4" Text="CANCEL" DialogResult="Cancel" /></px:PXPanel></px:PXSmartPanel>
Thank you for your support.
Best regards,
Purva Deshmukh