...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
Info | ||
---|---|---|
| ||
This article was written for a connector used with the separate Pack & Ship Extension (OnPrem or Per-Tenant). Mobile WMS - Implementing a new Shipping Provider Connector |
Use this event to
Create "Transport Orders" (or similar) in 3rd party Shipping App
Description
This event is triggered prior to a Warehouse Shipment being posted. You may use the event to:
- Update values at the Whse. Shipments (header or lines) prior to posting
- Create transport orders (or similar) for the Whse. Shipment (or use Pack & Ship Extension - OnPostPackingOnAfterPostWarehouseShipment (MOS) event if you want the Transport Order to be created after posting)
- Create transport order packages (or similar) based on untransferred license plates
- Mark untransferred license plates as now already Transferred to Shipping.
...
See also: Pack & Ship Extension - Write transaction data to 3rd party Shipping App
Template
/// <remarks>
/// Redirected from standard event OnAfterCheckWhseShptLine to new local event for more accessible "interface" (all neccessary events in Codeunit MOS Pack API)
/// </remarks>
[EventSubscriber(ObjectType::Codeunit, Codeunit::"MOS Pack API", 'OnPostPackingOnBeforePostWarehouseShipment', '', false, false)]
local procedure OnPostPackingOnBeforePostWarehouseShipment(var WhseShptHeader: Record "Warehouse Shipment Header"; var WhseShptLine: Record "Warehouse Shipment Line")
begin
end;
Example - Create Transport Order, Transport Order Packages and mark untransferred License Plates as now already Transferred to Shipping
In the example below the IdysActionManagement.WhseShipmtHdr_CreateTransportOrder() will create the Transport Order but not return any information about which exact Transport Order was created. This complicates the code and the example somewhat.
Since the new TransportOrder is unknown we are instead subscribing to event "IDYS Publisher".OnAfterCreateTransportOrderLine (a table describing the relation between the Sales Order Shipment and the Transport Order). This event will trigger during IdysActionManagement.WhseShipmtHdr_CreateTransportOrder. Based on the TransportOrderLine received with this event we are able to syncronize package information from our internal license plates tables to "IDYS Transport Order Packages".
...
[EventSubscriber(ObjectType::Codeunit, Codeunit::"MOS Pack API", 'OnPostPackingOnBeforePostWarehouseShipment', '', false, false)]
local procedure OnPostPackingOnBeforePostWarehouseShipment(var WhseShptHeader: Record "Warehouse Shipment Header"; var WhseShptLine: Record "Warehouse Shipment Line")
begin
UpdateQuantityToTransport(WhseShptLine);
if HasQuantityToTransport(WhseShptLine) then
CreateTransportOrder(WhseShptHeader); // May append to existing transport order
end;
local procedure UpdateQuantityToTransport(var _WhseShptLine: Record "Warehouse Shipment Line"): Boolean
var
WhseShptLine2: Record "Warehouse Shipment Line";
begin
// Simple implementation: Assuming everything is for ShipIt (currently not checking package + package type exists and is asociated to IDYS)
WhseShptLine2.Copy(_WhseShptLine);
if WhseShptLine2.FindSet() then
repeat
if WhseShptLine2."Qty. To Ship" <> 0 then begin
WhseShptLine2."IDYS Quantity To Send" := WhseShptLine2."Qty. To Ship";
WhseShptLine2.Modify(true);
end;
until WhseShptLine2.Next() = 0;
end;
local procedure HasQuantityToTransport(var _WhseShptLine: Record "Warehouse Shipment Line"): Boolean
var
WhseShptLine2: Record "Warehouse Shipment Line";
begin
WhseShptLine2.Copy(_WhseShptLine);
WhseShptLine2.SetFilter("IDYS Quantity To Send", '>0');
exit(not WhseShptLine2.IsEmpty());
end;
local procedure CreateTransportOrder(var _WhseShptHeader: Record "Warehouse Shipment Header")
var
IdysActionManagement: Codeunit "IDYS Action Management";
begin
IdysActionManagement.WhseShipmtHdr_CreateTransportOrder(_WhseShptHeader);
end;
/// <summary>
/// For each new transport order line created, transfer untransferred license plates to the transport order.
/// May transfer many or zero LP's (especially if all lines was transferred in a prior call to the event).
/// </summary>
[EventSubscriber(ObjectType::Codeunit, Codeunit::"IDYS Publisher", 'OnAfterCreateTransportOrderLine', '', true, true)]
local procedure OnAfterCreateTransportOrderLine(var TransportOrderLine: Record "IDYS Transport Order Line")
var
MobSessionData: Codeunit "MOB SessionData";
begin
if IsNullGuid(MobSessionData.GetPostingMessageId()) then
exit; // Not posting from Mobile WMS
InsertPackagesForTransportOrderLine(TransportOrderLine);
end;
internal procedure InsertPackagesForTransportOrder(_TransportOrderNo: Code[20]) _PackagesInserted: Integer
var
TransportOrderLine: Record "IDYS Transport Order Line";
begin
Clear(_PackagesInserted);
TransportOrderLine.Reset();
TransportOrderLine.SetRange("Transport Order No.", _TransportOrderNo);
if TransportOrderLine.FindSet() then
repeat
_PackagesInserted := _PackagesInserted + InsertPackagesForTransportOrderLine(TransportOrderLine);
until TransportOrderLine.Next() = 0;
exit(_PackagesInserted);
end;
/// <summary>
/// Insert all untransferred packages from all shipments related to a transport order line
/// </summary>
local procedure InsertPackagesForTransportOrderLine(_TransportOrderLine: Record "IDYS Transport Order Line") _PackagesInserted: Integer
var
WhseShipmentNo: Code[20];
begin
Clear(_PackagesInserted);
if _TransportOrderLine."Source Document Table No." = Database::"Sales Header" then begin
_TransportOrderLine.TestField("Source Document Type", 1); // 1 = Sales Order
_TransportOrderLine.TestField("Source Document No."); // Sales Order No
_TransportOrderLine.TestField("Source Document Line No."); // Sales Order No
// Transport order line source document table no. 36 -> whse. shipment line source type 37
WhseShipmentNo := GetWhseShipmentNoBySourceLine(Database::"Sales Line", _TransportOrderLine."Source Document Type", _TransportOrderLine."Source Document No.", _TransportOrderLine."Source Document Line No.");
_PackagesInserted := InsertPackagesForWarehouseShipment(WhseShipmentNo, _TransportOrderLine."Transport Order No.");
end;
exit(_PackagesInserted);
end;
/// <summary>
/// Insert all untransferred packages from a warehouse shipment
/// </summary>
local procedure InsertPackagesForWarehouseShipment(_FromWhseShipmentNo: Code[20]; _ToTransportOrderNo: Code[20]) _PackagesInserted: Integer
var
TransportOrderPackage: Record "IDYS Transport Order Package";
UntransferredLicensePlate: Record "MOS License Plate";
UntransferredLicensePlate2: Record "MOS License Plate";
PackageType: Record "MOS Package Type";
MosPackRegister: Codeunit "MOS WMS Pack Adhoc Reg-PostPck";
NextLineNo: Integer;
PackageTypeCode: Code[50];
begin
Clear(_PackagesInserted);
MosPackRegister.FilterUntransferredLicensePlatesForWarehouseShipment(_FromWhseShipmentNo, UntransferredLicensePlate);
if UntransferredLicensePlate.FindSet() then
repeat
if IsShippingProvider(UntransferredLicensePlate."Package Type") then begin
//
// First package only
//
if _PackagesInserted = 0 then begin
// Determine NextLineNo
TransportOrderPackage.LockTable();
TransportOrderPackage.Reset();
TransportOrderPackage.SetRange("Transport Order No.", _ToTransportOrderNo);
if TransportOrderPackage.FindLast() then
NextLineNo := TransportOrderPackage."Line No." + 10000
else
NextLineNo := 10000;
end;
//
// Any package
//
Evaluate(PackageTypeCode, UntransferredLicensePlate."Package Type");
PackageType.Get(PackageTypeCode);
TransportOrderPackage.Init();
TransportOrderPackage.Validate("Transport Order No.", _ToTransportOrderNo);
TransportOrderPackage.Validate("Line No.", NextLineNo);
NextLineNo := NextLineNo + 10000;
TransportOrderPackage.Validate("Package Type Code", PackageType."Shipping Provider Package Type");
if UntransferredLicensePlate.Weight <> 0 then
TransportOrderPackage.Validate(Weight, UntransferredLicensePlate.Weight);
if UntransferredLicensePlate.Height <> 0 then
TransportOrderPackage.Validate(Height, UntransferredLicensePlate.Height);
if UntransferredLicensePlate.Width <> 0 then
TransportOrderPackage.Validate(Width, UntransferredLicensePlate.Width);
if UntransferredLicensePlate.Length <> 0 then
TransportOrderPackage.Validate(Length, UntransferredLicensePlate.Length);
TransportOrderPackage.Insert(true);
_PackagesInserted := _PackagesInserted + TransportOrderPackage.Quantity;
UntransferredLicensePlate2 := UntransferredLicensePlate;
UntransferredLicensePlate2."Transferred to Shipping" := true;
UntransferredLicensePlate2.Modify(); // Do no modify record used for iteration due to next cursorplacement
end;
until UntransferredLicensePlate.Next() = 0;
exit(_PackagesInserted);
end;
/// <summary>
/// Collect all Whse Shipment No's related to a source (from open and posted warehouse shipments)
/// </summary>
local procedure CollectShipItTransportOrderNosByWhseShipment(_WhseShipmentNo: Code[20]; var _TransportOrderNos: Dictionary of [Code[20], Code[20]])
var
WhseShipmentLine: Record "Warehouse Shipment Line";
PostedWhseShipmentLine: Record "Posted Whse. Shipment Line";
begin
// From open Warehouse Shipment
WhseShipmentLine.Reset();
WhseShipmentLine.SetCurrentKey("No.", "Source Type", "Source SubType", "Source No.", "Source Line No.");
WhseShipmentLine.SetRange("No.", _WhseShipmentNo);
if WhseShipmentLine.FindSet() then
repeat
WhseShipmentLine.SetRange("Source Type", WhseShipmentLine."Source Type");
WhseShipmentLine.SetRange("Source Subtype", WhseShipmentLine."Source Subtype");
WhseShipmentLine.SetRange("Source No.", WhseShipmentLine."Source No.");
WhseShipmentLine.SetRange("Source Line No.", WhseShipmentLine."Source Line No.");
WhseShipmentLine.FindLast();
CollectShipItTransportOrderNosBySource(WhseShipmentLine."Source Type", WhseShipmentLine."Source Subtype", WhseShipmentLine."Source No.", WhseShipmentLine."Source Line No.", _TransportOrderNos);
WhseShipmentLine.SetRange("Source Type");
WhseShipmentLine.SetRange("Source Subtype");
WhseShipmentLine.SetRange("Source No.");
WhseShipmentLine.SetRange("Source Line No.");
until WhseShipmentLine.Next() = 0;
// From posted Warehouse Shipment
PostedWhseShipmentLine.Reset();
PostedWhseShipmentLine.SetCurrentKey("Whse. Shipment No.", "Source Type", "Source SubType", "Source No.", "Source Line No.");
PostedWhseShipmentLine.SetRange("Whse. Shipment No.", _WhseShipmentNo);
if PostedWhseShipmentLine.FindSet() then
repeat
PostedWhseShipmentLine.SetRange("Source Type", PostedWhseShipmentLine."Source Type");
PostedWhseShipmentLine.SetRange("Source Subtype", PostedWhseShipmentLine."Source Subtype");
PostedWhseShipmentLine.SetRange("Source No.", PostedWhseShipmentLine."Source No.");
PostedWhseShipmentLine.SetRange("Source Line No.", PostedWhseShipmentLine."Source Line No.");
PostedWhseShipmentLine.FindLast();
CollectShipItTransportOrderNosBySource(PostedWhseShipmentLine."Source Type", PostedWhseShipmentLine."Source Subtype", PostedWhseShipmentLine."Source No.", PostedWhseShipmentLine."Source Line No.", _TransportOrderNos);
PostedWhseShipmentLine.SetRange("Source Type");
PostedWhseShipmentLine.SetRange("Source Subtype");
PostedWhseShipmentLine.SetRange("Source No.");
PostedWhseShipmentLine.SetRange("Source Line No.");
until PostedWhseShipmentLine.Next() = 0;
end;
/// <summary>
/// Collect all ShipIt Transport Order No's related to a source (from open or posted warehouse shipment line)
/// </summary>
local procedure CollectShipItTransportOrderNosBySource(_SourceDocumentTableNo: Integer; _SourceDocumentType: Integer; _SourceDocumentNo: Code[20]; _SourceDocumentLineNo: Integer; var _TransportOrderNos: Dictionary of [Code[20], Code[20]])
var
TransportOrderLine: Record "IDYS Transport Order Line";
MosPackRegister: Codeunit "MOS WMS Pack Adhoc Reg-PostPck";
SourceDocumentHeaderTableNo: Integer;
begin
// Transport Order Lines are linked to header tables, not line tables
// Convert line table no. to header table no.
SourceDocumentHeaderTableNo := MosPackRegister.GetHeaderTableNo(_SourceDocumentTableNo);
TransportOrderLine.Reset();
TransportOrderLine.SetCurrentKey("Source Document Table No.", "Source Document Type", "Source Document No.", "Source Document Line No.", "Transport Order No.");
TransportOrderLine.SetRange("Source Document Table No.", SourceDocumentHeaderTableNo);
TransportOrderLine.SetRange("Source Document Type", _SourceDocumentType);
TransportOrderLine.SetRange("Source Document No.", _SourceDocumentNo);
TransportOrderLine.SetRange("Source Document Line No.", _SourceDocumentLineNo);
if TransportOrderLine.FindSet() then
repeat
TransportOrderLine.SetRange("Transport Order No.", TransportOrderLine."Transport Order No.");
TransportOrderLine.FindLast();
if _TransportOrderNos.Add(TransportOrderLine."Transport Order No.", TransportOrderLine."Transport Order No.") then;
TransportOrderLine.SetRange("Transport Order No.");
until TransportOrderLine.Next() = 0;
end;
/// <summary>
/// Get the single Whse Shipment No. related to a source line no. (from open or posted warehouse shipment)
/// Assuming a source line can only have a single associated whse. shipment line
/// </summary>
local procedure GetWhseShipmentNoBySourceLine(_SourceType: Integer; _SourceSubType: Integer; _SourceNo: Code[20]; _SourceLineNo: Integer): Code[20]
var
WhseShipmentLine: Record "Warehouse Shipment Line";
PostedWhseShipmentLine: Record "Posted Whse. Shipment Line";
begin
WhseShipmentLine.Reset();
WhseShipmentLine.SetCurrentKey("Source Type", "Source SubType", "Source No.", "Source Line No.", "No.");
WhseShipmentLine.SetRange("Source Type", _SourceType);
WhseShipmentLine.SetRange("Source Subtype", _SourceSubType);
WhseShipmentLine.SetRange("Source No.", _SourceNo);
WhseShipmentLine.SetRange("Source Line No.", _SourceLineNo);
if WhseShipmentLine.FindFirst() then
exit(WhseShipmentLine."No.");
PostedWhseShipmentLine.Reset();
PostedWhseShipmentLine.SetCurrentKey("Source Type", "Source SubType", "Source No.", "Source Line No.", "No.");
PostedWhseShipmentLine.SetRange("Source Type", _SourceType);
PostedWhseShipmentLine.SetRange("Source Subtype", _SourceSubType);
PostedWhseShipmentLine.SetRange("Source No.", _SourceNo);
PostedWhseShipmentLine.SetRange("Source Line No.", _SourceLineNo);
if PostedWhseShipmentLine.FindFirst() then
exit(PostedWhseShipmentLine."No.");
exit('');
end;
Version History
Version | Changes |
---|---|
MOS1.0.0 | Introduced |
...