SOLine DAC定价初始化问题:FieldDefaulting事件下金额仍为0
SOLine_CuryUnitPrice字段默认值始终为0的问题排查与优化方案
问题描述
在Acumatica中尝试通过SOLine_CuryUnitPrice_FieldDefaulting事件初始化销售订单行的单价,但无论逻辑如何执行,金额始终保持为0,原实现代码如下:
protected void SOLine_CuryUnitPrice_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e) { var row = (SOLine)e.Row; SOOrder order = (SOOrder) Base.Document.Current; BAccount un_compte=PXSelect<BAccount , Where<BAccount.bAccountID, Equal<Required<BAccount.bAccountID>>>>.Select(this.Base,row.CustomerID); if (row.InventoryID!=null) { InventoryItem un_article=PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>.Select(this.Base,row.InventoryID); string taxe=Convert.ToString(order.TaxCalcMode); if ((un_compte!=null) && (un_article!=null)) { if ((un_compte.GetExtension<BAccountExt>().Usrcattarifaireclient=="cat1") && (taxe=="N")) { decimal? tmp=un_article.GetExtension<InventoryItemExt>().Usrprxht1; e.NewValue=tmp; } if ((un_compte.GetExtension<BAccountExt>().Usrcattarifaireclient=="cat1") && (taxe=="G")) { decimal? tmp=un_article.GetExtension<InventoryItemExt>().Usrprxttc1; e.NewValue=tmp; } } } }
问题根源分析
row.CustomerID为空导致逻辑中断:FieldDefaulting事件触发时,SOLine行的CustomerID可能还未从订单头同步,导致查询不到BAccount记录,后续赋值逻辑完全不执行。order为空引发的潜在异常与取值错误:直接转换order.TaxCalcMode时,若Base.Document.Current为空(比如订单头未保存),会抛出空引用异常;同时将枚举类型转为字符串对比,易因枚举值字符串变化导致匹配失败。- 未覆盖全场景逻辑:当客户分类不是
cat1或计税模式不是N/G时,未设置e.NewValue,系统会沿用默认值0。 - 直接查询数据库的效率与缓存问题:使用
PXSelect.Select()直接查询数据库,未利用Acumatica缓存机制,既影响性能也可能获取到非最新数据。
修复后的代码实现
protected void SOLine_CuryUnitPrice_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e) { var row = (SOLine)e.Row; if (row == null) return; // 优先从订单头获取客户ID,避免行字段未同步 SOOrder order = Base.Document.Current; int? customerID = row.CustomerID ?? order?.CustomerID; if (customerID == null) return; // 从缓存获取BAccount,避免直接查库 BAccount un_compte = PXSelect<BAccount, Where<BAccount.bAccountID, Equal<Required<BAccount.bAccountID>>>>.Select(Base, customerID); if (un_compte == null) return; if (row.InventoryID == null) return; // 从缓存获取InventoryItem InventoryItem un_article = PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>.Select(Base, row.InventoryID); if (un_article == null) return; BAccountExt bAccountExt = un_compte.GetExtension<BAccountExt>(); InventoryItemExt invItemExt = un_article.GetExtension<InventoryItemExt>(); if (bAccountExt.Usrcattarifaireclient != "cat1") { // 非cat1客户的默认价格逻辑,可根据需求调整 e.NewValue = invItemExt.Usrprxht1; // 示例:默认取不含税价 return; } // 使用枚举类型对比,避免字符串转换错误 if (order?.TaxCalcMode == SOOrderTaxCalcMode.Exclusive) // "N"对应枚举值Exclusive { e.NewValue = invItemExt.Usrprxht1; } else if (order?.TaxCalcMode == SOOrderTaxCalcMode.Inclusive) // "G"对应枚举值Inclusive { e.NewValue = invItemExt.Usrprxttc1; } else { // 其他计税模式的默认值,可根据需求设置 e.NewValue = invItemExt.Usrprxht1; } }
关键优化点说明
- 优先从订单头取客户ID:解决SOLine行字段未同步导致的客户ID为空问题。
- 使用枚举类型对比计税模式:避免字符串转换的潜在错误,提升代码健壮性。
- 覆盖全场景逻辑:对非目标客户分类、其他计税模式设置明确的默认值,避免系统返回0。
- 利用缓存查询数据:通过
PXSelect.Select(Base, ...)从Acumatica缓存获取数据,提升性能并确保数据一致性。
进阶优化建议
如果需要更灵活的价格规则,建议使用Acumatica原生的**价格类别(Price Class)**功能,通过配置价格层级(客户、客户分类、库存等)实现自动化价格默认,无需编写硬编码逻辑,更符合系统架构且易于维护。
内容的提问来源于stack exchange,提问作者Xavier LARTEM
相关产品推荐
相关产品推荐

