基于销售订单通过代码创建采购订单,如何复制单据明细?
解决销售订单明细复制到采购订单的问题
我来帮你搞定这个需求!在Acumatica开发中,要把销售订单(SO)的明细复制到新创建的采购订单(PO)里,核心就是遍历SO的明细行,将对应字段映射到PO的明细行。结合你已经在SOOrderEntry扩展里创建PO的基础,我给你补全完整的实现代码,并解释关键步骤:
完整代码示例
namespace PX.Objects.SO { public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry> { // 自定义按钮触发PO创建(如果是自动触发,可放到RowPersisted等事件里) public PXAction<SOOrder> CreatePurchaseOrder; [PXButton(CommitChanges = true)] [PXUIField(DisplayName = "Create PO from SO")] protected virtual void createPurchaseOrder() { // 获取当前选中的销售订单 SOOrder currentSO = Base.Document.Current; if (currentSO == null) { PXTrace.WriteError("No sales order selected."); return; } // 初始化采购订单操作Graph POOrderEntry poGraph = PXGraph.CreateInstance<POOrderEntry>(); POOrder newPO = new POOrder(); // 配置PO头部基础信息 newPO.BranchID = currentSO.BranchID; // 直接复用SO的分支 newPO.OrderDate = DateTime.Now; newPO.Status = POOrderStatus.Open; // 供应商ID需要根据你的业务逻辑设置:比如从客户关联的供应商取,或手动指定 // 示例:假设从SO的CustomerID关联供应商(需要你自己实现关联逻辑) // newPO.VendorID = GetVendorFromCustomer(currentSO.CustomerID); newPO.VendorID = 123; // 测试用,替换成实际供应商ID // 插入PO头部到Graph newPO = poGraph.Document.Insert(newPO); // 遍历销售订单的所有明细行 foreach (SOLine soLine in Base.Transactions.Select()) { // 跳过无库存ID的行(比如服务类明细) if (soLine.InventoryID == null) continue; // 创建PO明细行并映射字段 POLine poLine = new POLine { BranchID = soLine.BranchID, InventoryID = soLine.InventoryID, OrderQty = soLine.OrderQty, // 复制SO的订单数量,可按需调整 UnitPrice = soLine.UnitPrice, // 复制SO的单价,若需供应商协议价可替换逻辑 UOM = soLine.UOM, Descr = soLine.Descr, SiteID = soLine.SiteID // 库存站点复用SO的设置 }; // 将明细行插入PO Graph poLine = poGraph.Transactions.Insert(poLine); // 若有其他需要更新的字段(比如成本代码、项目),在这里补充 // poLine.CostCodeID = soLine.CostCodeID; poGraph.Transactions.Update(poLine); } // 保存采购订单 poGraph.Actions.PressSave(); // 跳转到新创建的PO页面,方便用户查看 throw new PXRedirectRequiredException(poGraph, true, "Purchase Order Created Successfully"); } // 可选:根据客户ID获取对应供应商的辅助方法(示例) // private int? GetVendorFromCustomer(int? customerID) // { // // 这里实现你的业务逻辑,比如从CustomerExtension或关联表取供应商 // return null; // } } }
关键步骤说明
- 获取当前SO订单:通过
Base.Document.Current拿到用户当前操作的销售订单,避免空引用错误。 - 初始化PO Graph:用
PXGraph.CreateInstance<POOrderEntry>()创建采购订单的操作实例,所有PO的增改操作都通过这个Graph完成。 - PO头部配置:核心字段比如
BranchID直接复用SO的分支,供应商ID需要根据你的业务逻辑设置(比如客户对应固定供应商,或让用户选择)。 - 遍历SO明细:通过
Base.Transactions.Select()获取SO的所有明细行,逐个处理。 - 字段映射:将SO明细的
BranchID、InventoryID、OrderQty、UnitPrice等字段直接赋值给PO明细,按需调整(比如数量可能需要换算,单价可能取供应商协议价)。 - 保存并跳转:调用
poGraph.Actions.PressSave()保存PO,最后通过PXRedirectRequiredException跳转到PO页面,提升用户体验。
注意事项
- 如果需要自动创建PO(比如SO保存后自动生成),可以把逻辑放到
SOOrder的RowPersisted事件里,而不是按钮触发。 - 对于非库存类SO明细(比如服务),可以根据业务需求决定是否跳过或特殊处理。
- 单价逻辑如果需要取供应商的协议价格,可以替换
soLine.UnitPrice为POVendorPrice表的查询逻辑,获取对应物料的供应商协议价。
内容的提问来源于stack exchange,提问作者JM_caveman




