Acumatica生产订单维护界面批次/序列号生成自定义报错处理
Acumatica生产订单批次/序列号自定义生成问题解决
需求说明
在Acumatica生产订单维护界面(AM201500)的行明细标签页,默认Generate按钮生成的批次/序列号为000001这类纯数字序列,需修改为以当前生产订单号为前缀的格式,例如PP000004-000001、PP000004-000002,直到满足生成数量要求。
报错信息
首次尝试代码时出现以下验证错误:
[2024-10-07 03:16:01.919] PX.Objects.AM.ProdMaint_Extension中的Void GenerateNumbers(System.Action)方法标记了[PXOverride],但未在PXGraph中找到同名原方法。
[2024-10-07 03:16:08.479] 验证失败。
原尝试代码
using System; using PX.Data; using PX.Objects.IN; using PX.Objects.CS; using System.Collections; using System.Collections.Generic; using System.Text; using PX.Objects.AM.GraphExtensions; using PX.Common; using PX.Objects.Common; using PX.Objects.SO; using PX.Objects.AM.Attributes; using System.Linq; using PX.Objects.AM.CacheExtensions; using PX.Data.BQL.Fluent; using PX.Data.BQL; using PX.Objects.AR; using PX.Objects.CR; using PX.Objects.GL; using PX.Objects; using PX.Objects.AM; namespace PX.Objects.AM { public class ProdMaint_Extension : PXGraphExtension<PX.Objects.AM.ProdMaint> { #region Event Handlers // This method overrides the existing method tied to the Generate button [PXOverride] public virtual void GenerateNumbers(Action baseMethod) { // Call the base method to keep existing functionality (optional) baseMethod?.Invoke(); // Custom logic to generate Lot/Serial numbers based on production number var currentOrder = PXSelect<AMProdItem>.Select(Base).TopFirst; if (currentOrder == null) return; string productionNumber = currentOrder.ProdOrdID; // Get all generated material lines PXResultset<AMProdMatl> materialLines = PXSelect<AMProdMatl, Where<AMProdMatl.prodOrdID, Equal<Required<AMProdMatl.prodOrdID>>>> .Select(Base, currentOrder.ProdOrdID); int sequenceNumber = 1; foreach (AMProdMatl line in materialLines) { if (string.IsNullOrEmpty(line.LotSerialNbr)) continue; // Generate the new lot/serial number string newLotSerialNbr = $"{productionNumber}-{sequenceNumber:D6}"; // Update the lot/serial number line.LotSerialNbr = newLotSerialNbr; // Save changes Base.Caches[typeof(AMProdMatl)].Update(line); sequenceNumber++; } // Save changes to the database Base.Actions.PressSave(); } #endregion } }
调整后代码
public class ProdMaint_Extension : PXGraphExtension<ProdMaint.ItemLineSplittingExtension,PX.Objects.AM.ProdMaint> { #region Event Handlers //public IEnumerable GenerateNumbersDelegate(PXAdapter adapter); //public delegate IEnumerable GenerateNumbersDelegate(PXAdapter adapter); [PXOverride] public IEnumerable GenerateNumbers(PXAdapter adapter, Func<PXAdapter, IEnumerable> baseMethod) { //var result = baseMethod(adapter); //return result; // Call the base method to ensure the original functionality is executed var baseResult = baseMethod.Invoke(adapter); // Retrieve the current production order var currentProductionOrder = PXSelect<AMProdItem>.Select(Base).TopFirst; if (currentProductionOrder == null) { throw new PXException("No Production Order found."); } // Get the production order number var productionOrderNbr = currentProductionOrder.ProdOrdID; // Adjust this field as needed if (string.IsNullOrEmpty(productionOrderNbr)) { throw new PXException("Production Order Number is required."); } // Prepare a list to store the updated rows var resultList = new List<AMProdMatl>(); int sequenceNumber = 1; // Iterate over the results returned by the base method foreach (AMProdMatl row in baseResult.OfType<AMProdMatl>()) { // Generate the custom Lot/Serial number row.LotSerialNbr = $"{productionOrderNbr}-{sequenceNumber:D6}"; // Add the updated row to the result list resultList.Add(row); sequenceNumber++; } // Return the updated result list return resultList; } #endregion } }
问题分析与修正方案
核心问题
- 首次代码错误原因:Override的方法签名不匹配原方法。Generate按钮对应的方法属于
ProdMaint.ItemLineSplittingExtension扩展中的GenerateNumbers,其签名为IEnumerable GenerateNumbers(PXAdapter adapter),而非自定义的void GenerateNumbers(Action baseMethod),导致系统无法找到匹配的原方法。 - 调整后代码的不足:仅修改返回的列表对象未更新Acumatica的数据缓存,导致修改无法持久化;同时未处理重复点击Generate按钮时的序列重复问题。
修正后的完整代码
using System; using System.Collections.Generic; using System.Linq; using PX.Data; using PX.Objects.AM; namespace PX.Objects.AM { public class ProdMaint_Extension : PXGraphExtension<ProdMaint.ItemLineSplittingExtension, ProdMaint> { [PXOverride] public IEnumerable GenerateNumbers(PXAdapter adapter, Func<PXAdapter, IEnumerable> baseMethod) { // 执行原方法生成基础批次/序列号行 var baseResult = baseMethod(adapter); // 获取当前生产订单 var currentProdOrder = Base.ProdItem.Current; if (currentProdOrder == null || string.IsNullOrEmpty(currentProdOrder.ProdOrdID)) { throw new PXException("请先选择有效的生产订单"); } string prodOrdPrefix = currentProdOrder.ProdOrdID; int sequence = 1; // 遍历生成的物料行,更新批次/序列号 foreach (AMProdMatl matlRow in baseResult.OfType<AMProdMatl>()) { // 仅更新由Generate按钮生成的空或默认序列的行,避免重复修改 if (string.IsNullOrEmpty(matlRow.LotSerialNbr) || matlRow.LotSerialNbr.All(char.IsDigit)) { matlRow.LotSerialNbr = $"{prodOrdPrefix}-{sequence:D6}"; // 更新缓存中的记录,确保修改生效 Base.ProdMatl.Update(matlRow); sequence++; } } return baseResult; } } }
关键说明
- 正确的扩展继承:必须继承
ProdMaint.ItemLineSplittingExtension作为第一个泛型参数,因为Generate方法属于该扩展。 - 缓存更新:使用
Base.ProdMatl.Update(matlRow)更新Acumatica的数据缓存,确保修改能被系统识别并持久化。 - 防重复修改:增加判断条件,仅修改空值或纯数字的默认序列号,避免重复点击Generate时重复修改已自定义的序列号。
- 序列生成:使用
{sequence:D6}确保序列为6位补零格式,符合需求。
内容的提问来源于stack exchange,提问作者Tharidhi P
相关产品推荐
相关产品推荐

