Create Multiple LTL Orders |
[This is preliminary documentation and is subject to change.]
This walkthrough is for creating a multiple LTL shipments with AddOrder(OrderRequestV3); and then consolidating them with AddConsolidatedLTLShipment(LTLShipmentRequest); if you are creating a courier (Purolator, Canada Post, UPS) order then see the courier walkthrough. This walkthrough assumes that Purolator is handling customs; if you are using a different customs broker then ignore code related to Item data.
The difference between AddOrder and AddLTLOrder(LTLOrderRequest) is that shipments created with AddLTLOrder have been consolidated.
Create and populate an OrderRequestV3 object for each order.
In LTL, Packages represent containers instead of representing parcels. Adding Pallet information is typical, but not required.
OrderRequestV3 orderRequest = new OrderRequestV3 { Credentials = credentials, ShipToAddress = new Address { Name = "Test Customer Name", Add1 = "560 Kings Road", City = "Sydney", StateProv = "NS", PostalCode = "B1S1B8", Country = "CA" }, OrderNumber = "LTLOrder-TCN616", ShipMethod = "LTL", LabelType = "ZPLIMAGES", ShipDate = DateTime.Today, Packages = new[] // Optional for LTL - represents containers instead of parcels { new RequestPackageV3 { PackageID = "LTLPkg-TCN616-01", WeightUOM = "LB", Weight = 215, }, new RequestPackageV3 { PackageID = "LTLPkg-TCN616-02", WeightUOM = "LB", Weight = 65, }, new RequestPackageV3 { PackageID = "LTLPkg-TCN616-03", WeightUOM = "LB", Weight = 125, } }, Items = new[] { new RequestItemV3 { SKU = "x35135", CustomsDesc = "Books", Quantity = 865, TotalValue = (decimal)244.58, Currency = "CAD", CountryOfOrigin = "United States", NAFTAEligible = true, } } }; OrderRequestV3 orderRequest2 = new OrderRequestV3 { Credentials = credentials, ShipToAddress = new Address { Name = "Other Test Customer", Company = "Montreal Canadiens", Add1 = "1275 St. Antoine Street West", City = "Montreal", StateProv = "QC", PostalCode = "H3C5L2", Country = "CA" }, OrderNumber = "LTLOrder-TCN617", ShipMethod = "LTL", LabelType = "ZPLIMAGES", ShipDate = DateTime.Today, Items = new[] { new RequestItemV3 { SKU = "EXP003", CustomsDesc = "Books", HSCode = "490110", Quantity = 213, TotalValue = (decimal)2654.08, Currency = "CAD", CountryOfOrigin = "United States", NAFTAEligible = true, } }, }; return new List<OrderRequestV3> { orderRequest, orderRequest2 };
Submit each request. If the response indicates any errors, then fix and resubmit the request.
OrderResponse orderResponse = client.AddOrder(orderRequest); if (orderResponse.Status == (int)SeverityEnum.Error) { foreach (ResponseMessage message in orderResponse.Messages) { switch (message.Number) { case 1: // Invalid Credentials Console.Write("Invalid Credentials"); return orderResponse; case 3: // Selected ShipMethod is not supported case 81: // Air service not available. case 82: // Ground service not available. orderRequest.ShipMethod = "LTL"; break; } // Add cases to fix other errors.... } orderResponse = client.AddOrder(orderRequest); if (orderResponse.Status == (int)SeverityEnum.Error) return orderResponse; }
Print and apply the labels for any LTL containers. See ZPL page for more information.
Group all orders with by destination and assessorials (e.g. 9AM, 10:30AM, Saturday, Hold for pickup, dangerous goods, ...), and then consolidate each group.
// Assume all requests have the same ShipToAddress string[] orderNubmers = orderRequests.Select(o => o.OrderNumber).ToArray(); LTLPalletRequest[] pallets = orderNubmers.Select(orderNumber => new LTLPalletRequest { PalletNumber = orderNumber }).ToArray(); decimal weight = pallets.Count() * palletWeight + orderRequests.Sum(order => order.Packages.Sum(pkg => pkg.Weight)); LTLShipmentRequest ltlShipmentRequest = new LTLShipmentRequest { Credentials = credentials, ShipDate = DateTime.Today, ShipToAddress = orderRequests.First().ShipToAddress, OrderNumbers = orderNubmers, Pallets = pallets, GrossWeight = weight, ProNumber = proNumber, LTLShipmentNumber = ltlShipmentNumber, }; LTLShipmentResponse ltlShipmentResponse = client.AddConsolidatedLTLShipment(ltlShipmentRequest); if (ltlShipmentResponse.Status == (int)SeverityEnum.Error) { foreach (ResponseMessage message in ltlShipmentResponse.Messages) { switch (message.Number) { case 1: // Invalid Credentials Console.Write("Invalid Credentials"); return ltlShipmentResponse; case 2004: // ProNumber must be unique Console.Write("The ProNumber was not unique; attempting to use automatically generated ProNumber."); ltlShipmentRequest.ProNumber = null; break; case 2005: // LTLShipmentNumbers must be unique Console.Write("The LTLShipmentNumber was not unique."); ltlShipmentRequest.LTLShipmentNumber = null; break; } // Add cases to fix other errors.... } ltlShipmentResponse = client.AddConsolidatedLTLShipment(ltlShipmentRequest); if (ltlShipmentResponse.Status == (int)SeverityEnum.Error) return ltlShipmentResponse; }
When all containers and pallets are ready to ship (and any container labels have been attached), create a LTL Closeout to complete processing.
A CloseoutRequestLTL requires either ProNumbers or customer generated LTLNumbers to identify which pallets are included. To include any non-LTL parcels in the closeout, include either Pins or customer generated PackageIDs to identify the included parcels, and specify the number of non-LTL pallets. See the Closeout page for more information.
string[] proNumbers = validOrders.Select(o => o.ProNumber).ToArray(); string[] containerPins = validOrders.SelectMany(o => o.Packages.Select(p => p.TrackingNumber)).ToArray(); CloseoutRequestLTL ltlCloseoutRequest = new CloseoutRequestLTL { Credentials = credentials, ShipDate = DateTime.Today, LTLNumberType = "PRONUMBER", LTLNumbers = proNumbers, PackIDType = "Pin", PackageIDs = containerPins, ParsNumber = "12-14799632", // Only used by PARS customers. }; CloseoutResponseLTL closeoutResponseLTLResponse = client.CloseoutWithLTL(ltlCloseoutRequest); if (closeoutResponseLTLResponse.Status == (int)SeverityEnum.Error) { foreach (ResponseMessage message in closeoutResponseLTLResponse.Messages) { switch (message.Number) { case 1: // Invalid Credentials Console.Write("Invalid Credentials"); return closeoutResponseLTLResponse; case 71: // No packages to closeout - not found, not a courier package, label not printed, etc. return closeoutResponseLTLResponse; case 87: // PackIDType should be Pin or PackageID. ltlCloseoutRequest.PackIDType = "Pin"; break; case 88: // Package/container not found, or is not available for close out. // This can happen if the Package has been closed out or voided, or if it is from another account. return closeoutResponseLTLResponse; } // Add cases to fix other errors.... } closeoutResponseLTLResponse = client.CloseoutWithLTL(ltlCloseoutRequest); if (closeoutResponseLTLResponse.Status == (int)SeverityEnum.Error) return closeoutResponseLTLResponse; } // Handle any closeoutResponse.Documents
Print and apply the label for each pallet. See ZPL page for more information.