Acumatica基于屏幕Web Service创建发货单:错误排查与行项筛选咨询
Hey there! Let's break down your two main issues step by step—first fixing that confusing "Sales Order doesn't exist" error, then modifying your code to create shipments with only specific line items.
1. Troubleshooting the "Sales Order Number Doesn't Exist" Error
First, let's tackle why some orders work and others don't even though you can see them in Acumatica:
- Check Branch/Company Context: Acumatica's web services run in a specific branch/company context. If the failing orders belong to a different branch than what your web service session is set to, the system won't find them. Make sure you're explicitly setting the correct branch using
context.SetBranch(branchID)before fetching the sales order. - Verify Order Status & Visibility: Even if the order exists, it might be in a status that's not eligible for shipment (like Completed or Canceled)—but you said some work, so double-check the failing orders' status. Also, ensure the order isn't archived or restricted by security roles (your web service user needs full access to those orders).
- Clean Up Order Number Format: Sometimes extra spaces or case mismatches (if your system is configured for case-sensitive IDs) can cause this. Trim the order number string before passing it to the web service, e.g.,
salesOrderNumber.Trim(). - Refresh Web Service Context: Acumatica's web service caches data—try clearing the cache or reinitializing the context if you're reusing a session for multiple orders.
2. Creating Shipments with Only Specific Line Items
To generate a shipment that includes only certain line items from the sales order, you'll need to explicitly select which SOLine records to add to the Shipment instead of pulling all lines. Here's how to modify your code logic, building on the snippet you shared:
Option 1: Directly Create Shipment with Filtered Lines
First, fetch the target sales order and filter its line items to your criteria (e.g., only lines with a specific inventory ID or line type):
// Fetch the sales order (ensure correct context/branch is set) SOOrder salesOrder = PXSelect<SOOrder, Where<SOOrder.orderNbr, Equal<Required<SOOrder.orderNbr>>>>.Select(Base, targetOrderNbr); if (salesOrder == null) { throw new PXException($"Sales Order {targetOrderNbr} does not exist or is not accessible."); } // Example: Filter lines where InventoryID equals "PROD-001" var filteredLines = PXSelect<SOLine, Where<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>, And<SOLine.inventoryID, Equal<Required<SOLine.inventoryID>>>>>.Select(Base, salesOrder.OrderNbr, "PROD-001");
Then, create the shipment and add only those filtered lines:
// Initialize the shipment with core order details Shipment shipment = new Shipment(); shipment.OrderNbr = salesOrder.OrderNbr; shipment.CustomerID = salesOrder.CustomerID; shipment.WarehouseID = salesOrder.WarehouseID; // Match order's warehouse shipment = Base.Caches[typeof(Shipment)].Insert(shipment); // Add filtered sales order lines to the shipment foreach (SOLine line in filteredLines) { ShipmentLine shipmentLine = new ShipmentLine(); shipmentLine.ShipmentNbr = shipment.ShipmentNbr; shipmentLine.OrderNbr = line.OrderNbr; shipmentLine.OrderLineNbr = line.LineNbr; shipmentLine.InventoryID = line.InventoryID; shipmentLine.Qty = line.QtyRemaining; // Ship remaining quantity, or set a specific value // Copy other critical fields (UnitPrice, Discount, etc.) from SOLine shipmentLine.UnitPrice = line.UnitPrice; Base.Caches[typeof(ShipmentLine)].Insert(shipmentLine); } // Save the completed shipment Base.Actions.PressSave();
Option 2: Adjust Pre-Shipment (PSOrder) Logic If Using That Flow
If you're working with the pre-shipment workflow from your snippet, modify the line selection when building the PSOrder before converting it to a shipment:
PSOrders.Current = psorderrec; if (psorderrec.Status == PSOrderStatus.Hold) { throw new PXException(String.Format("Preshipment {0} is On Hold and cannot be generated.", psorderrec.OrderNbr)); } // Clear any existing pre-shipment lines to avoid including all lines Base.PSOrderLines.Delete(Base.PSOrderLines.Select()); // Fetch and filter the sales order lines you want to include var filteredSOLines = PXSelect<SOLine, Where<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>, And<SOLine.lineType, Equal<Required<SOLine.lineType>>>>>.Select(Base, psorderrec.OrderNbr, SOLineType.Inventory); // Add only filtered lines to the pre-shipment foreach (SOLine soLine in filteredSOLines) { PSOrderLine psLine = new PSOrderLine(); psLine.OrderNbr = psorderrec.OrderNbr; psLine.InventoryID = soLine.InventoryID; psLine.Qty = soLine.QtyRemaining; psLine.UnitPrice = soLine.UnitPrice; Base.PSOrderLines.Insert(psLine); } // Convert pre-shipment to a shipment Base.Actions["ConvertShipment"].Press();
Key Tips
- Always validate that filtered lines exist before creating the shipment—throw a meaningful error if no lines match your criteria (e.g.,
throw new PXException("No eligible line items found for shipment.")). - Double-check that all required fields are copied from the sales order line to the shipment/pre-shipment line to keep financial and inventory data accurate.
- Test with a small set of orders first to confirm both the "order not found" error is resolved and the line filtering works as expected.
内容的提问来源于stack exchange,提问作者Sameer Wagh

