@SaiKrishnaV I recently worked on a similar requirement and thought it would be helpful to share this as a reference.
Please find the relevant source code below. The implementation follows a similar approach and should give you a good starting point for your scenario.
While integrating this, please ensure that any dependent methods or supporting logic from the base code are also included within the CreateNumbers method. This is important to maintain consistency with the original behavior and to avoid any missing dependencies or runtime issues.
Additionally, you may want to review how the base implementation handles validations and edge cases, and incorporate those as needed to ensure a complete and robust solution.
public PXAction<POReceipt> GenerateLotSize;
[PXButton]
[PXUIField(DisplayName = "Generate Lot", MapEnableRights = PXCacheRights.Select,
MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable generateLotSize(PXAdapter adapter)
{
POReceiptLine line = Base.transactions.Current;
LotSerOptions lotSerOptions = Base.Caches<LotSerOptions>().Current as LotSerOptions;
WMSPOLotSerOptionsExt lotSerOptionsExt = lotSerOptions?.GetExtension<WMSPOLotSerOptionsExt>();
if (line != null && line.ReceiptQty > 0 && lotSerOptionsExt != null && lotSerOptionsExt.UsrWMSItemLotSize > 0
// && Base.Document.Current?.ReceiptNbr.Contains(PX.Objects.AP.Messages.NewKey) == true
)
{
decimal? breakQty = lotSerOptionsExt.UsrWMSItemLotSize;
decimal? remainingQty = line.BaseReceiptQty - line.UnassignedQty;
// 1️⃣ First split: update the original line
decimal? currentQty = remainingQty >= breakQty ? breakQty : remainingQty;
// Update existing line to first lot-size chunk
line.BaseQty = currentQty;
SetLineQtyFromBase(line);
// Persist change to the existing line
Base.transactions.Update(line);
remainingQty -= currentQty;
while (remainingQty > 0)
{
decimal? nextQty = remainingQty >= breakQty ? breakQty : remainingQty;
// Clone line to avoid overwriting original
POReceiptLine newLine = PXCache<POReceiptLine>.CreateCopy(line);
newLine.BaseQty = nextQty;
CreateNumbers(newLine, Convert.ToDecimal(nextQty), false);
remainingQty -= nextQty;
}
}
return adapter.Get();
}
public virtual void CreateNumbers(POReceiptLine line, decimal deltaBaseQty, bool forceAutoNextNbr)
{
PXResult<InventoryItem, INLotSerClass> item = ReadInventoryItem(line.InventoryID);
POReceiptLineSplit split = base.Base1.LineToSplit(line);
INLotSerClass lsClass = item;
if (line != null)
LineCounters.Remove(line);
INLotSerTrack.Mode mode = GetTranTrackMode(line, lsClass);
if (!forceAutoNextNbr
&& lsClass.LotSerTrack == INLotSerTrack.SerialNumbered
&& lsClass.AutoSerialMaxCount > 0
&& lsClass.AutoSerialMaxCount < deltaBaseQty
&& (mode & INLotSerTrack.Mode.Create) > 0)
deltaBaseQty = lsClass.AutoSerialMaxCount ?? 0;
ILotSerNumVal lotSerNum = ReadLotSerNumVal(item);
foreach (POReceiptLineSplit lssplit in INLotSerialNbrAttribute.CreateNumbers<POReceiptLineSplit>(base.Base1.LineCache, lsClass, lotSerNum, mode, forceAutoNextNbr, deltaBaseQty))
{
string LotSerTrack = (mode & INLotSerTrack.Mode.Create) > 0
? lsClass.LotSerTrack
: INLotSerTrack.NotNumbered;
split.SplitLineNbr = null;
split.LotSerialNbr = lssplit.LotSerialNbr;
split.AssignedNbr = lssplit.AssignedNbr;
split.LotSerClassID = lssplit.LotSerClassID;
if (split is ILSGeneratedDetail gsplit && lssplit is ILSGeneratedDetail glssplit)
gsplit.HasGeneratedLotSerialNbr = glssplit.HasGeneratedLotSerialNbr;
if (!string.IsNullOrEmpty(line.LotSerialNbr) && (LotSerTrack == INLotSerTrack.LotNumbered || LotSerTrack == INLotSerTrack.SerialNumbered && line.Qty == 1m))
{
split.LotSerialNbr = line.LotSerialNbr;
}
if (LotSerTrack == INLotSerTrack.SerialNumbered)
{
split.UOM = null;
split.Qty = 1m;
split.BaseQty = 1m;
}
else
{
split.UOM = null;
split.BaseQty = deltaBaseQty;
split.Qty = deltaBaseQty;
}
if (lsClass.LotSerTrackExpiration == true)
split.ExpireDate = ExpireDateByLot(split, line);
PXCache<POReceiptLineSplit>.Insert(Base, base.Base1.Clone(split));
deltaBaseQty -= split.BaseQty.Value;
}
if (deltaBaseQty > 0m && (lsClass.LotSerTrack != INLotSerTrack.SerialNumbered || decimal.Remainder(deltaBaseQty, 1m) == 0m))
{
line.UnassignedQty += deltaBaseQty;
}
else if (deltaBaseQty > 0m)
{
POReceiptLine oldLine = PXCache<POReceiptLine>.CreateCopy(line);
line.BaseQty -= deltaBaseQty;
SetLineQtyFromBase(line);
if (Math.Abs(oldLine.Qty.Value - line.Qty.Value) >= 0.0000005m)
{
base.Base1.LineCache.RaiseFieldUpdated(LineQtyField.Name, line, oldLine.Qty);
base.Base1.LineCache.RaiseRowUpdated(line, oldLine);
}
}
if (line.UnassignedQty > 0)
RaiseUnassignedExceptionHandling(line);
}