Acumatica自定义需求:实现销售订单到发货单及发票的自定义字段复制
Acumatica自定义字段复制解决方案
错误原因
你遇到的“销售表不存在‘Test Field’列”错误,是因为直接使用PXSelect<SOOrder,...>查询时,Acumatica会尝试从数据库表中读取字段,但自定义字段UsrTestField是定义在SOOrderExt扩展类中的,并非数据库原生列,因此无法直接通过基础表查询获取。
修复后的代码实现
1. 自定义字段扩展类(保留原有正确定义)
public class SOOrderExt : PXCacheExtension<SOOrder> { [PXDBString(50, IsUnicode = true)] [PXUIField(DisplayName = "Test Field")] public string UsrTestField { get; set; } public abstract class usrTestField : PX.Data.BQL.BqlString.Field<usrTestField> { } } public class SOShipmentExt : PXCacheExtension<SOShipment> { [PXDBString(50, IsUnicode = true)] [PXUIField(DisplayName = "Test Field")] public string UsrTestField { get; set; } public abstract class usrTestField : PX.Data.BQL.BqlString.Field<usrTestField> { } } public class SOInvoiceExt : PXCacheExtension<SOInvoice> { [PXDBString(50, IsUnicode = true)] [PXUIField(DisplayName = "Test Field")] public string UsrTestField { get; set; } public abstract class usrTestField : PX.Data.BQL.BqlString.Field<usrTestField> { } }
2. 发货单复制销售订单字段扩展
改用RowInserting事件在发货单创建时处理字段复制,通过Acumatica的Cache机制自动加载扩展字段,避免直接数据库查询的问题:
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry> { protected void _(Events.RowInserting<SOShipment> e) { SOShipment shipment = e.Row; if (shipment == null) return; // 获取发货单关联的第一条销售订单行 SOShipLine shipLine = Base.Transactions.Select().FirstTableItems.FirstOrDefault(); if (shipLine == null) return; // 从Cache中获取销售订单数据,自动加载扩展字段 SOOrder soOrder = PXSelect<SOOrder, Where<SOOrder.orderType, Equal<Required<SOOrder.orderType>>, And<SOOrder.orderNbr, Equal<Required<SOOrder.orderNbr>>>>>.Select(Base, shipLine.OrigOrderType, shipLine.OrigOrderNbr); if (soOrder == null) return; SOOrderExt soExt = soOrder.GetExtension<SOOrderExt>(); SOShipmentExt shipmentExt = shipment.GetExtension<SOShipmentExt>(); // 复制自定义字段 shipmentExt.UsrTestField = soExt.UsrTestField; } }
3. 发票复制发货单字段扩展
同样使用RowInserting事件,在发票创建时复制发货单的自定义字段:
public class SOInvoiceEntryExt : PXGraphExtension<SOInvoiceEntry> { protected void _(Events.RowInserting<SOInvoice> e) { SOInvoice invoice = e.Row; if (invoice == null) return; // 获取发票关联的第一条发货单行 SOInvoiceLine invoiceLine = Base.Transactions.Select().FirstTableItems.FirstOrDefault(); if (invoiceLine == null) return; // 从Cache中获取发货单数据,自动加载扩展字段 SOShipment shipment = PXSelect<SOShipment, Where<SOShipment.shipmentType, Equal<Required<SOShipment.shipmentType>>, And<SOShipment.shipmentNbr, Equal<Required<SOShipment.shipmentNbr>>>>>.Select(Base, invoiceLine.ShipmentType, invoiceLine.ShipmentNbr); if (shipment == null) return; SOShipmentExt shipmentExt = shipment.GetExtension<SOShipmentExt>(); SOInvoiceExt invoiceExt = invoice.GetExtension<SOInvoiceExt>(); // 复制自定义字段 invoiceExt.UsrTestField = shipmentExt.UsrTestField; } }
关键说明
- 使用
RowInserting事件替代Persist方法,确保字段在创建单据时立即复制,而非等到保存阶段。 - 依赖Acumatica的Cache机制获取主记录,系统会自动加载对应的扩展类字段,避免直接查询数据库导致的列不存在错误。
- 针对发票场景新增
SOInvoiceExt扩展类,确保自定义字段能存储到发票单据中。
内容的提问来源于stack exchange,提问作者Aldrin Muranganwa
相关产品推荐
相关产品推荐

